Compare commits

...
Author SHA1 Message Date
Larry Gritz a0ea2668db CHANGES for release 2019-07-04 12:00:16 -07:00
marsupial 6ef53ccc64 Respect lockgeom default when building from commands. Remove ASSERT during ReParameter (#1032) 2019-07-02 23:58:24 -07:00
Larry Gritz 9b5cc9ba18 Port FindOpenEXR.cmake fixes from OIIO (#1022) 2019-05-22 12:19:25 -07:00
Larry Gritz 69d5c3e292 Bump version after release 2019-05-06 10:36:20 -07:00
Larry Gritz 6343afc07c CHANGES 2019-05-04 13:01:33 -07:00
Larry Gritz 3c957cf4ca Add build-time option to set gcc C++ ABI (ported from OIIO) (#995) 2019-04-16 09:26:24 -07:00
Larry Gritz bc0c58b49f Extend linearstep and smooth_linearstep to color/point/vector/normal (#994) 2019-04-16 09:25:49 -07:00
Larry Gritz bb92d7b8c3 oslc: slight adjustment to assignment typechecking (#993)
Consider int=float to be a warning, not an error.
This is partly because C allows it and we ran accross some
examples where it seems more strict than necessary.
(Of course it works without warning if you use a cast, showing
that any trucation is intentional.)
2019-04-10 16:49:25 -07:00
Larry Gritz 096005a6a4 Improve oslc type error detection for variable declaration with init
Turns out that some of the various type checking we do for simple
assignment,

    x = y

was not being checked at all for variable declaration with initialization,

    Type x = y

So this patch adds the necessary checks. And also goes back and improves
the error messages for regular variable assignment, changing from messages
like

    Cannot assign 'float' to 'int'

to the more clear (I think, because it names the variable, and looks
more like the grammatical construct being complained about)

    Cannot assign int i = float
2019-04-05 17:06:59 -07:00
Larry Gritz 14bbc14875 Bump version after release, and some minor README/CHANGES fixes. 2019-04-01 10:39:53 -07:00
Larry Gritz fd8ad23e85 CHANGES for release 2019-04-01 00:12:44 -07:00
Larry Gritz 02b84cfc90 Fix oslc assertion on type constructor for unknown struct (#988)
The assertion was not needed, errors issue before this code is reached.
2019-03-30 11:08:08 -07:00
Larry Gritz 7f750c900a Fix oslc assertion when passing init-lists to array parameters (#983)
It's easiest to explain the situation by example:

    void receive_array_3 (float array[3]) { }
    void receive_array_any (float array[]) { }

    receive_array_3 ({1.0, 2.0, 3.0});
    receive_array_any ({1.0, 2.0, 3.0});

Both of these would fail/crash by hitting an assertion in oslc.  The
general pattern is when passing an initializer-list (like just saying
`{ a, b, c }`) to a user function formal parameter that's an array.
They failed for somewhat different reasons if the formal parameter
was a concretely-sized array or if it was an unsized array.

A little bit of typecheck-fu handles this case.
2019-03-20 23:19:08 -07:00
Larry Gritz 156103daf2 Improve warnings about ill-advised use of comma operator (#978)
We previously had warnings that attempted to catch mistakes in using
the "comma operator" when the user intended an "aggregate type
constructor", for example:

    color x = (a, b, c);    // comma operator! equivalent to: x = c;
    color x = color(a,b,c); // this is what they probably meant

However, the way we implemented the warning was specific to assignment:

    x = (a, b, c);

and variable declaration with initialization:

    color x = (a, b, c);

But it missed similar bugs in other constructs, for example

    color x = Cdiffuse * (a, b, c);

Here the user surely intends to multiply Cdiffuse channel-by-channel
with color(a,b,c), but what they will actually get is Cfiffuse scaled
by float c.

This patch changes the strategy for this warning, no longer tied to
variable declaration or assignment, but more generally any time the
comma operator is used inside expression parentheses, it will give a
warning.
2019-03-14 10:59:02 -07:00
Larry Gritz bb89ec0afd Simplify flex/bison handling (#977)
Rely on CMake's own finding of flex/bison, simplifying our code to
just the helpful shortcut macro. Also make finding these REQUIRED,
which makes an easier-to-interpret error message than simply not
defining the macro.
2019-03-14 10:58:09 -07:00
Larry Gritz 51ebc17d43 Bump appveyor llvm release (and use pre-installed LLVM rather than building) 2019-03-12 13:44:22 -07:00
Larry Gritz a95a987b3a OptiX: always seem to need --cuda-path flag, even for cuda 9 2019-03-06 14:48:56 -08:00
Larry Gritz 18a1ee0e44 FindLLVM: Make more robust to library configuration of llvm (#976)
In particular, some system distributions bundle everything in one
libLLVM, without a separate libLLVMMCJIT.
2019-03-05 16:14:36 -08:00
aconty 69851a3159 Forbid LPE repetitions inside groups (#972)
This is not useful in practice and we've seen a case of exponential DFA
state blowup in issue #971 because of its accidental use. This does not
make LPEs totally robust to ReDoS but prevents this particular mistake.
2019-02-19 10:33:06 -08:00
Larry Gritz 1faae7e25c Bump version after release 2019-02-19 10:32:57 -08:00
Larry Gritz f8dc41c556 CHANGES 2019-02-01 11:55:58 -08:00
Larry Gritz cc70c2e37b Improve thread safety of OSLCompiler (#953)
Fixes #654.

There's a problem with the lock we use to protect the global
`oslcompiler` pointer -- it's locked for the duration `osl_parse_buffer`
(where it's assigned), but it is used and also cleared to NULL after the
lock is released (in particular, the clearing that happens in compile()
and compile_buffer().

The solution is to move the lock itself to compile/compile_buffer, and
do all of the assignment, use, and clear within the scope of that lock.

I think this went unnoticed for so long because most of us highly
multithread the shader execution (and runtime optimization), but not the
initial compilation -- except for Issue #654, and my sincere apologies for
letting that slip through the cracks.
2019-01-12 09:08:46 -08:00
Larry Gritz be86932223 Some C++ definition and other touch-ups (#950)
Some C++ definition and other touch-ups
Partly ported from equivalent changes in OIIO recently.
2019-01-12 09:02:26 -08:00
Larry Gritz 4019fadcb5 Fix custom namespace vs symbol hiding clash
I guess everbody who builds with NAMESPACE=... to customize OSL's namespace
must (like we do) pick a name that include the substring "OSL".
Because if they don't... a bunch of public API symbols will be improperly
hidden!

Oops. Seems like the most foolproof solution is that if a custom namespace
is supplied that doesn't include the substring "OSL", have the build
script prepend "OSL_". Then the symbol hiding regex will work.

(You may object: "But then you're not using exactly what they asked for!"
Correct, but remember we are already overriding their literal choice by
automatically appending the OSL version number as well.)

While there, also take care to hide symbols containing "pvt", which I
think should not be exposed, despite the fact that they're in the main
OSL namespace.
2019-01-11 14:13:47 -08:00
Larry Gritz 6d99c3b943 Get rid of suspicious spurious reference (#959) 2019-01-04 16:35:49 -08:00
Larry Gritz befa64183c Fix transformc with derivs when using OCIO (#960)
I have no idea how this ever worked. In fact, it must never have, because
our checked-in reference output was wrong. But it kept matching the same
wrong until it didn't, and became a different kind of wrong on at least
one machine.

When doing transformc, where the space names necessitated using OCIO for
the transformation math, and only for the derivative case (the non-deriv
was fine all along), we were simply passing the wrong stride parameters
to the colorproc->apply() call.

Also, I noticed that we were trying to save a per-context "last
transformation" to avoid the lookup when doing repeats of needing the
same colorproc (basically, a 1-item LRU cached lookup of the
colorproc). But we never saved the space name, so the cache was not
operating.
2019-01-04 16:34:26 -08:00
Larry Gritz 78f8480c07 Reword error with less yelling (#952)
Fixes #811
2019-01-04 10:46:40 -08:00
Larry Gritz 1dfef8bc49 Fix bug with inverse spline (#954)
We were clipping the range incorrectly for bezier, where it needs
to step by 3 CVs for each span. Worked ok for the other spline
types, which step by 1.

Add a test that verify that a spline designed to give a f(x)=x response
does so, and also that its inverse is perfect.

Fixes #778
2019-01-04 10:46:08 -08:00
Larry Gritz 6d34914ccc Fix bug in oslc loop code generation (#947)
The problem was specific to using an integer variable directly as the
loop test, rather than a comparison. So for example, this would work
fine:

    i = 3;
    while (i > 0) {
        --i;
    }

But this would loop forever:

    i = 3;
    while (i) {
        --i;
    }

Because of a hilarious chain of events, this would eventually lead to
the optimizer thinking that since the value of i was nonzero at the
beginning of the loop, it must be equivalent to while(1). There was a
subtle assumption that the scope of the loop control variable would be
entirey inside the condition code. That was true of the the temporary
created to hold the result of "i > 0", but not true of the direct use of
i itself.  The solution is to force it to create a bool comparison
(which turns into the same machine code later anyway, so there is no
efficiency issue here).

Fixes #776
2019-01-04 10:46:04 -08:00
Larry Gritz 99297424d9 oslc: Fix crash when encountering for (;;) (#951)
An empty conditional clause of a `for` statement was leading to bad
things. It's understood that `for (;;)` means `for (;1;)`, so just
make sure that happens when parsing.

Fixes #688
2019-01-04 10:45:58 -08:00
Larry Gritz 4678327640 Fix group_name, group_init_name, group_entry_name (#957)
I didn't notice this in Tim's code before today, but he made the
retrieval of these group attributes more complex than they needed to be.
Instead of messing with pointers (which we avoid), you can just directly
getattribute(name,string&). So now we use that. Also eliminate group_name
entirely, since it's redundant with the existing groupname.
2019-01-04 08:22:57 -08:00
Larry Gritz d782bcead3 Change %.8g formatting to %.9g (#949)
%.9g is needed to totally guarantee full precision preservation for all
possible float32 values.
2019-01-03 11:59:15 -08:00
Larry Gritz e2f20d0a00 Tweaks to pdf docs building 2018-12-23 13:20:44 -08:00
marsupial fa657029cb Fix array initialization counter (#948) 2018-12-18 23:08:15 -08:00
Larry Gritz 44516d0c4f Improve oso output efficiency with less redundant work on retrieve_source (#938)
To make debugging easier and be more human-readable, oso files are
littered with comment lines reproducing the source code, so that you can
see which source corresponds to which "oso assembly".

The workhorse here is the retrieve_source(filename,line) function. But
it was unspeakably inefficient, reading the entire source file every
time an op needed a different source file than the previous op, and
scanning the file to find the n-th line *every* time. This seems like
the lookup is O(n^2) and also that we're rereading source files
potentially thousands of times.

Theory: If we cache all the files we read, so we never read each source
file more than once, and also remember which line we used last (we tend
to go in increasing order in a source file) and resume the search from
there, backtracking only when the line is less than the last one needed,
it ought to be blazingly fast!

Practice: It barely makes any difference.  Compiling all 600 MaterialX
source osl files takes 30 seconds on my laptop, and this fix saves maybe
a second or two at most.

Oh well. But I already made the change, so may as well keep the more
efficient algorithm. Perhaps there are other cases where it gives a
bigger advantage.
2018-12-13 09:19:49 -08:00
Larry Gritz 7de8a0f3a4 testshade: check that no leftover errors are in the TS or IC (#939) 2018-12-13 09:19:49 -08:00
Larry Gritz 5fed2f2fe7 Docs typo fix
[ci skip]
2018-12-13 09:19:49 -08:00
Larry Gritz 899b1b31cc Demote writing to non-output function parameters to be a warning. (#944)
It was never supposed to be allowed. It used to be ignored in most
cases, error neither detected nor issued. PR #878 "fixed" it to detect
the error. But there were too many shaders that did it, users are
confused and it breaks things.

So this patch downgrades it from an error to a warning. If you ignore
the warning, you get what you deserve (which is probably not
bad... people lived with it for years). Anybody who wants it to be fully
illegal can always compile with -Werror to turn warnings in to full
errors.

I also "uniformized" two separate error messages on the same general
topic, so they look the same.
2018-12-13 09:18:09 -08:00
Larry Gritz 9c2c9b0eb0 Bump version after release 2018-12-13 09:17:57 -08:00
Larry Gritz 550096985e Extremely minor docs source fix 2018-12-05 11:50:39 -08:00
Larry Gritz 64c2d66a39 Release 1.10 2018-12-01 18:01:58 -08:00
Larry Gritz 53469220b4 Docs touch-ups and prepare release candidate 2018-11-26 15:27:13 -08:00
Larry Gritz 2332f60ec5 Improve error reporting when compiling from memory buffer (#937)
The `OSLCompiler::compile_buffer()` method, which is used to compile
osl source code from a memory buffer, had unhelpful error messages
such as:

    <buffer>:11: error: Unknown struct name: x

because of course, there was no filename, just a memory buffer. This
is ugly and confusing to users.

This patch adds an optional parameter to compile_buffer() that lets you
supply a "filename" to use for error reporting of the mem-buffer-compiled
shader. This makes pretty error messages if you supply a good name:

    zap.osl:11: error: Unknown struct name: x

An application of this is shown with the changes in osltoy.

For my own debugging purposes, I also implemented a `-buffer` option to
oslc, which just forces a file read, compile-from-buffer, and then file
write, so that it's easier for me to exercise the buffer code path.
2018-11-26 14:26:06 -08:00
Larry Gritz 31e1f4c6b3 SS::optimize_group: add optional ctx pointer (#936)
If supplied, it uses the passed context if needed, rather than allocating
a temporary one.
2018-11-26 14:25:46 -08:00
Larry Gritz e20730af4e Bump version after tag 2018-11-20 16:11:42 -08:00
Larry Gritz f51907c205 Docs and other touch-ups for 1.10 beta 2018-11-20 11:47:12 -08:00
Larry Gritz 5b246b0d3e Fix crash with struct parameter assignment from function call. (#934)
Edge case that triggered an assert.
2018-11-20 10:49:06 -08:00
Larry Gritz ccc6d5015b Add options to skip compiling of shaders or MX shaders (#935) 2018-11-19 14:07:03 -08:00
darkhorse64 b33262f50d Export struct OSLQuery::Parameter for Windows (#933) 2018-11-18 11:12:26 -08:00
Christopher Kulla 74eb73a0c8 Fix texture3d lookups with derivatives (#932)
One side was trying to make use of dresultdz while the llvm codegen was always providing nullptr. Since the shading system only supports Dual2 at the moment for derivative lookups, it seems more consistent to forget about trying to come up with a meaningful Z derivative for the time being.
2018-11-08 10:28:58 -08:00
Larry Gritz fd3bba1e13 oslc: Fix type constructor dealing with ambiguity in function return types (#931)
If you have a function that is polymorphic based on return type --
like cellnoise, which could return a float or a color -- you will get
a warning about the ambiguity in certain situations which you can resolve
with an explicit type cast:

    (float) cellnoise (u, v)    // the cast disambiguates which you want

But Thiago found that the similar idiom using a type constructor (rather
than a cast) like this:

    float (cellnoise (u, v))    // fails to disambiguate cellnoise?

fails to disambiguate and gives a warning about ambiguous types (it will
choose the float-returning kind, but will warn about the ambiguity, which
will be an error if you compile with `-Wall`).

This patch fixes the problem by making ASTtype_constructor::typecheck()
aware that float(expr) ought to expect expr to be a float if possible,
and also triple(expr,expr,expr) should expect all three of the channel
expressions to disambiguate to float. It previously made no such inference
in those cases. Note, however, that triple(expr) did previously know that
the expression ought to prefer to disambiguate to the same triple type.

While investigating, I also saw that the oso generated by that same
constructor sometimes did an extra unnecessary temporary assignment, so
while I was ast it I also fixed that with the changes you see to
ASTtype_constructor::codegen (in fact, these changes altered more code
than the type checking part).

Fixes #930
2018-11-06 15:26:17 -08:00
Larry Gritz 93839e1c42 Bump dev version 2018-11-01 14:46:32 -07:00
Larry Gritz 158efc4d6c Rebuild docs
[ci skip]
2018-11-01 14:44:32 -07:00
Larry Gritz 9d64eb55f5 CHANGES/docs
[ci skip]
2018-11-01 14:39:06 -07:00
Larry Gritz d25f8d6435 Wean ourselves off of 'operator int' of ustring, and bug fixes (#929)
OIIO's ustring has an "operator int()" that is possibly ill-advised, as
claimed by Thiago Ize and John Haddon from an oiio-dev thread from back
in 2015 (I'm doing some old thread necromancy). They claimed that an
operator int (or for that matter bool) could result in subtle bugs from
type conversions you don't expect to happen.  The fact that there's no
equivalent operator int/bool for std::string or std::string_view
bolsters their argument.

I started off just trying to eliminate all OSL uses that assume this
operator would work (the proper idiom is simply `!str.empty()`). Along the
way, I found *TWO* bugs related to this -- one in osltoy and one
when constant folding "wrap" arguments to texture functions! So Thiago
and John were surely right, and I am appropriately chastened and
belatedly trying to find a way to get rid of the troublesome operator.
2018-10-29 11:40:20 -07:00
Larry Gritz 7d8b0b2540 CMake refactor (#928)
* Use the "official" FindOpenImageIO.cmake from OIIO (recently
  added). This necessitates some renaming, for example standard use of
  OPENIMAGEIO_ROOT_DIR.

* Change inconsistent naming of OSLHOME (and OSL_HOME) to the more
  standard OSL_ROOT_DIR.

* Copy updated FindOpenEXR.cmake from recent OIIO (and related changes).

* Eliminate all of testsuite/MaterialX, which was not used, never fully
  worked, and was certainly out of date with our MX support. If we want
  to add unit tests for MX shaders, I think I will take a completely
  different approach. So for now, just eliminate the clutter.

* Eliminate site/pixar/Makefile-bits, which they say they no longer use
  (some of those customizations were the very last uses of some weird
  custom stuff in our older FindOpenEXR.cmake, now eliminated).
2018-10-26 14:27:37 -07:00
marsupial ab44f553ca SPI: Default to use vanilla boost (#927) 2018-10-24 18:00:17 -07:00
Larry Gritz 637fe3e833 Fix typos in docs & comments
[ci skip]
2018-10-22 15:56:28 -07:00
Larry Gritz d76bfeec4b Fixes to make recent osltoy changes not break against OIIO 1.8 (#926)
Recent changes used a new ImageBufAlgo convention only present in current
OIIO master, not older 1.8 that we still promise compatibility with.

Didn't catch this before because the Travis tests don't install qt and
therefore don't build osltoy at all. Add qt to the Mac travis setup so
that it at least builds to prevent this from happening.
2018-10-15 12:44:05 -07:00
Larry Gritz 524ffe306a Change to search path rules for .oso files (#925)
New rules:

* If NO "searchpath:shader" attribute is specified to the ShadingSystem,
  the current working directory (".") will be searched.

* If a searchpath is specified, it will look ONLY in those directories,
  in order. The current working directory will only be searched if
  it is listed among the paths.
2018-10-12 17:02:21 -07:00
Larry Gritz 27266344fb Rewrite OSOReaderToMaster::hint (#923)
Zap is seeing sporadic (but frustraingly impossible to reproduce) crash
reports from inside this function, specifically in the part that parses
%argrw hints.

There was a longstanding comment:   // FIXME -- use string_view ops here

So, sure, rewrite the whole thing using string_view and Strutil::parse
functions, and remove the assertions, and put extra guards to make sure
we aren't acessing a symbol or op (via blah.back()) if there aren't any
in the vector yet, and pretty much just let it ignore or be robust to any
malformed hints.

I've never seen a repro case, so I don't know that this will fix it, but
it's programmed a lot more defensively now, so hopefully there will be
no further crashes (after I backport this to whatever version Zap is
using).  I even put in an error message for a certain way to malform
%argrw, in the hopes that it might give us a clue, but even that is just
a guess.
2018-10-12 15:13:57 -07:00
Larry Gritz c0a4cdea9d Update MaterialX README
[ci skip]
2018-10-12 10:22:11 -07:00
Larry Gritz 5e839afa52 Fix docs typo about matrix construction 2018-10-11 14:28:36 -07:00
Larry Gritz 157e4657fa Fix oslc read/write error for regex_search/regex_match (#922)
For these functions, oslc failed to mark the results output param as
write only.

Fix the bug in oslc, and also put in a provision in loadshader that will
correct the old already-compiled incorrect files.

Thanks to Steena Monteiro from Intel for pointing this out!
2018-10-05 15:50:32 -07:00
Larry Gritz c66ccb6fb5 Test against llvm7 and gcc8, several gcc8-related warning fixes (#921) 2018-10-01 11:27:48 -07:00
Christopher Kulla f865b5b252 Fix compile errors inside LLVM 7 on CentOS 7.3 from buggy system inttypes.h header 2018-09-27 15:23:31 -07:00
marsupial 3a080f70b0 Add Pixel magnifier to osltoy when alt is held down (#918) 2018-09-26 13:04:58 -07:00
Jino Park 66f52f8644 Remove useless nullptr check (#920) 2018-09-26 10:40:53 -07:00
Larry Gritz 64dadf9b8f Minor changes to build with clang 7. (#917)
The changes in oslcomp.cpp seem only to be necessary with particular
combinations of clang7 and older llvm. Which we don't recommend!  Better
to use the same generation of clang and llvm. But in any case, may as
well make set those options explicitly.

Also switch SPI to build with clang7/llvm7 by default.
2018-09-19 16:25:55 -07:00
Larry Gritz d6c375bc29 Travis: add test entry against LLVM 6.0 2018-09-14 22:51:11 -07:00
Larry Gritz 0169ab732e Fix testrender bug with undefined order of operations (#916)
A suspicious line in testrender seems to depend on undefined behavior
regarding the specific order of evaluation of quantities in a math expression.
It has been there forever, but only seems to fail on certain builds of gcc 5
and possibly clang 7.

It's just a one-line fix to remove the order-of-evaluation ambiguity.

Thanks, Tim Grant, for pointing this out!
2018-09-14 22:41:58 -07:00
Larry Gritz ffc58557a3 osltoy: add 'pause' and 'reset' buttons (#914)
'Pause' (which changes its label to 'continue' when paused) stops the
clock and continued execution of the shader, until 'continue' is hit.

'Reset' sets the time counter back to 0.0 again.

It starts in a paused state, and starts the clock the first time you
successfully compile a shader.
2018-09-14 18:05:20 -07:00
Shane Ambler e9191e2440 Remove use of a fixed path to call bash (#915)
* use a less rigid path to call bash
2018-09-14 10:30:34 -07:00
Larry Gritz 5ec807c081 Replace quick_floor with ifloor (912) 2018-09-05 09:55:33 -07:00
Larry Gritz b4843323b0 Fix cellnoise bug (912)
WARNING: possible visible change in procedural patterns

It's expected that cellnoise(x) == cellnoise(floor(x)), but we found an
ugly bug wherein cellnoise internally used a helper function
quick_floor, which is supposed to take the floor of a float argument and
return its integer equivalent. But unfortunately it had a really odd
error: when x was an exact negative integer, it gave the value for the
next smaller integer.

    quick_floor( 1.00) ==  1
    quick_floor( 0.01) ==  0
    quick_floor( 0.00) ==  0
    quick_floor(-0.01) == -1
    quick_floor(-0.99) == -1
    quick_floor(-1.00) == -2    // WRONG!!! Should be -1
    quick_floor(-1.01) == -2

This in turn caused cellnoise lookups of exact negative integer values
to be incorrect lookups of the next lower-numbered cell, i.e.,
cellnoise(i) having the same value as cellnoise(i-epsilon), but again,
only for i<0 and i==floor(i) exact integer values.

Now, if your shader made a visual representation of callnoise(x,y), it
would look just fine, unless a particular x,y fell *exactly* on integer
coordinates, in which case it would be ever so slightly off (by being
the color of the square immedately to the left instead of to the right,
as it should be, say).  Nobody would ever notice that.

Also, if your shader took the floor before passing to cellnoise, like:
cellnoise(floor(x),floor(y)), it would also *look* correct, though the
negative values would be wrong, since cellnoise(-1,-1) would have
returned the value that should have been cellnoise(-2,-2), etc., but
you never would have noticed that.

But... there were some possible uses of cellnoise where it was behaving
very strangely, and the main place you would notice this is certain
types of "voronoi" noises where you are lookup up cellnoise values while
looping over adjacent lattice points. (Thanks, Zap, for noticing this,
and so sorry that there was a legit bug here!)

It was a very slight possible problem for perlin style noise as well,
but since those noises are "continuous" and defined by gradients, you
really, really, would not have known that the occasional pixel had noise
results that were ever so slightly off in its derivatives only at those
isolated integer lattice points. I think no visible artifacts were
discernable under real-world conditions.

The solution is to bite the bullet and replace the clever (but extremely
minor) speedup for computing floor, with a legit floor call.  It's ever
so slightly more expensive if you isolate the cost of just raw cellnoise
calls, but in the context of a real render I don't think you'll be able
to measure it.

WARNING: This may change the appearance of certain "Voronoi" patterns,
or possibly other uses of cellnoise as random number sequences. It also
changes the appearance of "Gabor" noise, which internally also used the
faulty quick_floor in such a way that it affects the whole pattern.

Note that this should NOT change the appearance of any of the
perlin-style noises, and you may not notice any change for most ordinary
uses of cellnoise, either.

I changed the oslnoise unit tests to check that this is working
properly, and updated all of the noise unit tests that generate images
to "center" the patterns so that they visibly display the negative
regions of the noise domain (they had all shown only positive domain,
which is probably inviting trouble if there was ever a noise bug that
only affects what happens for negative values or right on the axes).
This caused a lot of the reference images to change, even for the tests
of noise patterns that were unaffected. Also, I took the chance to merge
a few of the signed/unsigned tests for less repetition.

I'm very sorry about this; changing the appearance of noise functions is
not something we take lightly, we do it only as a last resort. It was
clearly wrong before and had some very unexpected failure modes. But I'm
only making this fix in master, which is destined to be "OSL 2.0", so I
figure it's as good a time as any to make a change that could possibly
make visible changes in some shaders.

If you see this as some kind of major betrayal that will screw up your
productions, let me know and if pressed I can perhaps make some kind of
emulation of the old buggy behavior for people who need to preserve it.
But I'd rather not do that if it's not absolutely necessary.
2018-09-05 09:55:29 -07:00
Larry Gritz f0bc9a91f3 LLVM 7.0 and clang 7 compiles (#910)
* Modernize the way we generate memset and memcpy ops -- we still had
  some artifacts of LLVM 3.x; since LLVM 4+, there has been a more
  direct way to generate the equivalent of memset/memcpy (and be
  careful, the API changes slightly for LLVM 7.0).

* Some header file changes with llvm 7.

* Minor ref-vs-ptr miscellany for WriteBitcodeToFile and CloneModule.

* Slight change to addPassesToEmitFile call signature.
2018-08-17 21:21:06 -07:00
Larry Gritz d78dfc146e MaterialX build strategy overhaul (#909)
* Radically simplify build_materialX_osl.py -- It previously had a whole
lot of unused complexity by being able to build multiple template
expansions at once, and to do ALL template expansions without the cmake
system. But we never used it that way. So simplify it to handle a single
shader and type at a time, which is how it's called from our cmake
scripts. This makes it easier to maintain and removes a lot of redundant
logic that was duplicated (possibly incorrectly) between cmake and
python.

* Modify MaterialX build process to handle "OTHERTYPE" so we can get a
templated cross-product of two type lists (though by default, OTHERTYPE
is "none", so it's just a linear list of types we expand to). OTHERTYPE
is also allowed to be "same" which means it's the same as the first TYPE.
This makes it easy to make a templated node where for a bunch of types T,
it has a T,T version, and also a T,float version.

* Implement MX "convert" node, which utilizes the ability to have two
templated types.

* Clean-up of lots of nodes where we special cased the vecN/colN versus
itself, versus vecN/colN versus float. Now that we can template on two
types, these all simplify to one template for the "same" case and the
"float" case.

* File/node naming convention: for all nodes that can be templated on
a single type, we continue to call the OSL shader mx_thefunction_thetype.osl
(and .oso). But for all nodes that can be templated on two types,
(add, smoothstep, etc.), they will be named mx_thefunction_type1_type2.osl.
2018-08-09 12:00:14 -07:00
Larry Gritz 0e4296de4b MaterialX cleanup: ramp4, texture mapping, matrix math (#907)
* MaterialX: fix definition of ramp4 top vs bottom

In recent times, it's been decided that "top" always refers to v=1 and
"bottom" refers to v=0.

* MaterialX: various clean ups to texture mapping nodes

* image node: wasn't honoring addressmode or filtertype params.

* Fixes to triplanarprojection: wasn't properly normalizing by the
  combined weight of the three views, wasn't honoring filtertype param,
  wasn't forcing periodic wrap.

* Implement the new "tiledimage" node.

* MaterialX: extend add/sub/mul/div to include matrices per 1.36 spec
2018-08-06 18:40:34 -04:00
Larry Gritz 22443fc4e9 Whitespace cleanup
[ci skip]
2018-07-28 12:33:25 -07:00
Larry Gritz 3e3b528c73 MaterialX 1.36 additions: rotate, transforms, rgb/hsv, extract, separate (#905)
* Add a variant of rotate() that just takes an axis, rotate about the origin.

* MaterialX: add rotate node (new with MaterialX 1.36)

* rotate2d note is kept for back-compatibility, but considered deprecated, since it was dropped from 1.36.

* MaterialX: implement new transformpoint, transformvector, transformnormal nodes

* MaterialX: add new nodes rgbtohsv, hsvtorgb

* MaterialX: add new 1.36 node 'hsvadjust', deprecate 'hueshift'

* MatrialX: Add new 1.36 nodes: extract, separate
2018-07-28 08:45:03 -07:00
Larry Gritz 7a56abdfb0 SPI specific touch-ups for OptiX support 2018-07-25 18:10:04 -07:00
timgrant 99ed27a535 More OSL+OptiX progress: support for strings (#902)
* Add a device_string type for representing static strings on CUDA devices. Update LLVM codegen to generate and handle device_strings. Add mechanisms to register and query integer IDs associated with device_strings.

* Move the DEVICE_STRING_PARAM macro.

* Remove some redundant calls in addGlobalVariable.

* Remove OptiX exceptions, since they are not well supported.

* Unify the OptiX and non-OptiX path for passing the noise name.

* Re-add osl_printf to rend_lib.cu.

* Add a very basic print test for testoptix.

* Make the warmup launch in testoptix optional. Fix minor indentation problem in rend_lib.cu.

* De-unify the OptiX and non-OptiX path for passing the noise name. Fix some formatting issues with rend_lib.cu.

* Simplify test_print.osl.

* Add ASSERTs to certain OptiX-only functions as a sanity check.

* Add detailed comment to device_string.h.

* Slightly rework device_string example in wrapper.cu.

* Add some macros to make registering device_strings less painful.

* Pulled more of the 'standard' strings into strdecls.h. Added DeviceStrings namespace. Using the STRDECLs in setup_string_tags.

* Update the comment in device_string.h with usage notes for the STRDECLs.

* Changes to compile and link device_strings.cpp separately.

* Working on a device memory string table.

G# ot string assignment seemingly working.

Cleanup.

* Simplify StringTable a little.

* Pack the string length and hash value into the string table, and add strlen and hash functions to rend_lib.cu.

* Replace vector with map in StringTable.

* Handle OptiX printf with wrong args by printing warning and ignoring print call.

* Add rudimentary check for collisions between global variable names.

Fix a bug in the offset alignment logic for the string table.

Add getchar. Add StrRep type for casting raw DeviceString pointers to make accessing hash and len more convenient.

Modified ustring to use cudaMallocManaged. Modified StringTable to use the ustring pointers instead of a separate table. Not working with varying strings.

* Use regular device memory instead of Unified Memory for string table. Add assert to limit active devices to 1. Miscellaenous comments and refactoring.

* Added better re-casting macro for DeviceString. Added comments. Added test for string ops. Misc. small fixes.

* Update OptiX version-finding logic in CMake.

* Rename the CUDA-specific GlobalVariable functions. Use string format when constructing the mangled variable names.

* Add TODO comments about string arrays in CUDA/OptiX.

* Add license to stringtable.cpp.
2018-07-25 18:07:35 -07:00
Larry Gritz 3c8f214461 Add sign() and log() to vector struct types. (#904)
Ass missing `sign` node to MaterialX.
Change MaterialX `ln` implementation from log2 to correct log.
2018-07-25 17:55:05 -07:00
Derek Haase 4d3d0c4804 Add lots of new MaterialX 1.36 support
Add sin, cos, tan, atan2, ceil, sqrt, exp, determinent, ln, and
transpose operators

Rename exponent operator to power

Rename pack to combine

add extract operator

Add conversion operators:
color2->vector2
color->vector
color4->vector4
vector2->color2
vector->color
vector4->color4

Matrix inversion operator.
2018-07-21 09:40:11 -07:00
Derek Haase de63270a19 Add more functions to color2, color4, vector2, vector4
ceil, sqrt, exp, log2, sin, cos, tan, asin, acos, atan2
2018-07-21 09:40:11 -07:00
Larry Gritz 585e3dcfba Speed up parsing of long initializer lists. (#901)
If you have something like

    float table[65536] = { 0.1, 0.35, -0.72, ... }

This might take TENS of seconds for oslc to parse, because the mechanics
of how that long list of values is parsed -- it involves a singly-linked
list of ASTNodes, and with each new one, we are appending to the far end
of the linked list. This leads to an O(n^2) parsing time, where n is the
length of the list.

The straightforward (but wrong!) way to fix it is to change the Bison
grammar for init_expression_list from "left-recursive" to "right-recursive".
That makes it natural to prepend items (O(1)) to the accumulating list,
but it's very inefficient for Bison and can overrun Bison's fixed-size
parsing stack. Bison docs discurage use of right-recursion in grammars,
since left-recursion grammar can parse arbitrarily deep recursive
structures in a fixed memory size.

OK, so how do we fix this? Trickery! Keep left recursion, but accumulate
in the reverse order (i.e., prepend, not append), and then do a single
reverse of the backwards list at the very end. That makes the whole
parsing affair O(n) instead of O(n^2).

Sounds good, but one final wrinkle is that the list we need to reverse
is is a raw pointer to the head, followed by ref-counted pointers to
each subsequent element. In order to keep from accidentally freeing
things if the ref counts reach zero, we have our fancy reverse()
function rely on a brand spanking new feature of OIIO's intrusive_ptr<>
to add a release() method (https://github.com/OpenImageIO/oiio/pull/1986).
But since that doesn't exist in older OIIO, to avoid a compatibility
break, we only do our special left recursion + backwards list + reversal
trick if the OIIO version we build against has that new feature.
Otherwise, it's #ifdef'ed out and we just do it the old slow way.

This fixes OSL issue #723, and for the pathological test case presented
in that issue, it improves compile time (on my laptop) from ~26 seconds
to 0.4 seconds.

I also checked that this funny business with the reversal doesn't slow
down the simple cases for ordinary shader. Compiling the whole
collection of 500+ MaterialX shaders took about 20.5 seconds, and with
the new parsing code is exactly the same, or at least, too close to
accurately discern in the time trials.
2018-07-19 18:13:50 -07:00
Christopher Kulla addb70fa65 Fix incorrect array length on unbounded arrays specified via relaxed parameter type checking (#900) 2018-07-18 13:51:58 -07:00
Larry Gritz 18893a8484 docs
[ci skip]
2018-07-16 22:33:59 -07:00
Larry Gritz fb3e125063 ShaderType/ShaderUse refactoring (#899)
Deprecate the use of shader "types" (surface, displacement, etc.)
designated in OSL source code. Those words will still be accepted for
backward-compatibility, but they are no longer required or encouraged.
Generic "shader" type is the only one we will talk about as we move
forward.

Excise the ShaderUse enum. Renderers (or non-renderers using OSL for
programmability) are allowed to determine and document whatever type of
shader "uses" they want to support. The only enforcement from the
liboslexec side is that all the shader nodes within one group must be
tagged with the same "use" string.

The "use" parameter to ShadingSystem::Shader() is intended to be removed
entirely, eventually. However, that's the first of three (optional)
parameters to Shader(), so it's a subtle change that can break renderers
in annoying and confusing ways if we do it all at once, so we'll do it
in stages: For this major release, we will make all three parameters to
Shader() be required (no optional params), which even if it generates a
compile-time error for a renderer, is a very obvious one to fix. Then in
a later major release (2.1?), after we know that all renderer code is
making 3-argument calls to Shader(), we will introduce a 2-argument
version that lacks a "use" parameter (can't break renderer code) and
deprecate the 3-argument call that has the useless "use" parameter, and
then in a later release, we can remove the 3-argument version once and
for all.

Add new queries for shader groups: "globals_read" and "globals_write",
which return a bit field of which shaderglobals fields will be read or
written, respectively, by the shader group after it's optimized.
The bitfield meanings are given by the new enum class SGBits, defined
in shaderglobals.h. This is easier to query (as an `int`) than to sort
through the list of strings you'd get with "globals_needed", and allows
renderers (if they so desire) to (a) verify that shaders don't use or
modify globals they aren't supposed to, for the type of shader use they
are being used for; (b) potentially to avoid any expensive computations
that would need to be performed to prepare certain shaderglobals fields,
for shader groups that won't end up using them.

Also make the `I` global variable be writeable and clarify that if a
global is writeable, it's writeable from any shader type, and we don't
intend to do differing checks based on shader type.
2018-07-12 18:23:55 -07:00
Larry Gritz 9d6d30b13c Fix compiler error on MSVC -- suspicious static_assert (#898)
In dual.h, we static_assert involving std::initializer_list<T>::size(),
which is constexpr only for C++14 and on. This seemed to work for clang
and gcc, but MSVC 15 doesn't like it. Guard it so that it only applies
for C++ >= 14, in which the constexpr makes it more certainly legal for
static_assert to reference initializer_list::size().

Fixes #897
2018-07-09 10:24:52 -07:00
Larry Gritz 388f0370c7 Warning fixes on gcc6 (#896)
For some reason, this built ok on TravisCI, but not on the partciular
gcc6 version I had at work. Minor fix.
2018-07-03 16:46:41 -07:00
Larry Gritz 182c02b28a Fix test output to not fail on Windows 2018-06-15 10:27:06 -07:00
Larry Gritz 6fb409d6eb Fix MSVS potential build problem with iso646.h macros (#892) 2018-06-14 15:13:11 -07:00
Larry Gritz ae64eadf48 Update trig ref output after recent OIIO change 2018-06-14 14:27:14 -07:00
Larry Gritz 4afb8d4cf0 Fix build break after recent OIIO changes 2018-06-14 14:13:21 -07:00
Alex Fuller 7db5293d96 Flex/bison wincompat patch (#891) 2018-06-04 14:10:22 -07:00
Christopher Kulla d595393728 Specify gcc-toolchain for clang explicitly for SPI builds 2018-05-30 16:02:32 -07:00
Larry Gritz f4b5846c28 Update test ref output after recent OIIO fmath.hchanges 2018-05-18 14:39:31 -07:00
Larry Gritz 0766be6328 Fixes for OIIO change to imageio create function signature (#889) 2018-05-18 14:34:20 -07:00
McHox d8c755bf5a fixed typo (#886) 2018-05-07 23:09:32 -07:00
Larry Gritz d02cbb9b7c RendererServices: make non-abstract (#885)
Allowing the base class to be used as a trivial RendererServices, can
be helpful for certain applications where not much renderer functionality
is needed.
2018-05-04 18:10:47 -07:00
Larry Gritz ad3d40c8df changes
[ci skip]
2018-04-29 18:16:10 -07:00
Larry Gritz 3b72f78f66 Updates to handle OIIO ImageInput refactor. (#882) 2018-04-27 16:59:41 -07:00
Larry Gritz 61fd99d06e Fix error_repeats: clearing happened for getattribute instead of attribute (#883) 2018-04-26 10:08:57 -07:00
timgrant a39f965544 OptiX noise functions (#877)
* Changes to compile OSL noise functions for CUDA: Add CUDA-compatible variant of ImathMatrix.h; add HOSTDEVICE macro to noise functions; modify CMake build for liboslexec to compile and link multiple shadeops sources when compiling for CUDA; change Module link order when compiling to PTX; bump minimum CUDA version to 8.0; set CUDA path for clang according to CUDA version; add CUDA_TARGET_ARCH CMake variable.

* Add testoptix-noise to testsuite.

* Fix up the CMake build flags in liboslexec. Remove the HOST_DEVICE macro from some hash functions in opnoise.cpp. Clean up a few unneeded preprocessor macros.

* Change a few hash function signatures to take void* instead of float*, and cast as appropriate.
2018-04-11 20:17:22 -07:00
Larry Gritz edf7d842f7 Reduce extreme cost of oslnoise_test on CI and DEBUG runs 2018-04-09 16:40:54 -07:00
Larry Gritz 98d71786f8 SS attrib "error_repeats" controls suppression of repeat errors & warnings (880)
Previously, exactly identical error and warning messages (including from
shaders themselves) printed the first time and suppressed the duplicates.
The rationale is that an error in a shader could easily turn into thousands
of error messages if duplicates weren't suppressed.
There wasn't a way to turn this behavior off.

Now it's controlled by ShadingSystem attribute "error_repeats", an int,
which has default value 0 (do not issue repeated errors). If changed
to 1, repeated errors and warnings will be allowed to pass to the error
handler, without suppression in the ShadingSystem.

Furthermore, the act of setting the attribute (to either 0 or 1) has the
side effect of clearing the list of remembered errors. This means that
even if you want error suppression, poking it in this way will reset the
counters, which might be a handy thing to do at the start of each frame
(if you are using a single ShadingSystem to render multiple frames) so
that you start the counts fresh for each render, rather than for each
ShadingSystem.
2018-04-09 15:45:58 -07:00
Larry Gritz 0efbf04f5c CHANGES 2018-04-05 09:14:03 -07:00
Larry Gritz 1e336440d9 Fix redundant command line flag entry 2018-04-05 09:09:41 -07:00
Larry Gritz 379107eab3 Errors for writing to read-only function parameters or globals (#878)
It has been a longstanding problem that oslc did not properly flag
attempts to write to function paramseters that were not marked as
'output'.

I've rigged this so that in the current master (and any past releases,
assuming we backport this to release branches), it will just be a
warning. In future versions, it will be a full error. That should give
people some advanced warning (no pun intended) to fix any problems that
this catches that previously went unnoticed.
2018-04-05 09:08:35 -07:00
Larry Gritz 36c714000f CHANGES and docs 2018-03-31 14:49:05 -07:00
Larry Gritz 9a301e8153 Add forgotten -Werror to oslc help message (#879) 2018-03-28 10:23:25 -07:00
Larry Gritz d67b469898 Fix confusing argument order issue for testshade (#875)
Testshade set certain command line options as a by-product of certain
other ones, and that introduced a weird order dependency to the arguments
that was confusing. In particular,

    testshade -O0 myshader

worked as expected, but

    testshade myshader -O0

set the options (including optimization level) when parsing myshader,
before it got to the -O0.

So this patch simply makes sure that the shader options are
re-established after all arguments are parsed.
2018-03-27 13:38:23 -07:00
Larry Gritz ca1d377056 Fix OptiX build for SPI 2018-03-26 16:07:39 -07:00
Matt Johnson 75aeade555 specify the VERSION and SOVERSION when building library shared objects (#876)
In this change, we specify the VERSION and SOVERSION properties of library
shared objects so that the SONAME in the shared object contains the OSL version
number suffix (major.minor). This also results in the build creating versioned
symlinks back to the installed shared objects. Code that links against the
libraries can then link against a specific version of OSL such that the correct
version can be dynamically linked at runtime.

This follows a similar pattern to the one used in OpenImageIO.
2018-03-26 15:36:50 -07:00
Larry Gritz 4d5eb61328 Bump LLVM minimum to 4.0, drop support for 3.9 (#874) 2018-03-19 11:33:18 -07:00
timgrant 6f611fc009 OSL-to-PTX compilation (#868)
* Apply initial round of changes to liboslexec to support PTX generation. Add function decorators to shadeops in llvm_ops.cpp and to functions in dual.h to support device compilation. Depends on modified version of fmath.h from OIIO, and includes a local version of ImathVec.h from OpenEXR that has been modified to support CUDA compilation.

* Update testoptix to reflect changes to liboslexec. testoptix now loads scenes from the testsuite, compiles the ShaderGroups to PTX, and attempts to render the scene using flat shading. The implementation is limited and very experimental.

* Update the testsuite to reflect the current state of testoptix.

* Get rid of the 'native_target' flag and initialize all LLVM targets in all cases.

* Use ustring::format to construct OptiX variable names, instead of std::string concatenation.

* Don't delete m_const_map entries in destructor, since they are owned by the LLVM Module.

* Cache whether or not the renderer supports OptiX.

* Use the serialization script from liboslexec for testoptix.

* Fix wrong header include.

* Add OPTIX_EXTRA_LIBS CMake variable. Add include path for ILMBase. Specify CUDA path when compiling with clang.

* Refactor ptx_compile_group: replace deprecated default CodeModel option, simplify target/layout option, reword some assert messages.

* Add virtual destructor to Primitive struct in testoptix to appease pedantic compilers.

* Add check for NVPTX target to CMake build.

* Add guard against redefinition of HOSTDEVICE macro. Rename HOSTDEVICE IMATH_HOSTDEVICE. Add decorators to Imath::Vec4 types. General reformatting of ImathVec_cuda.h.

* Move OSL_HOSTDEVICE definition into oslconfig.h, and update includes accordingly.
2018-03-16 18:15:41 -07:00
Larry Gritz 539a5c4f7b Make runtest.py be python 2/3 agnostic (#873) 2018-03-06 15:56:37 -08:00
Larry Gritz 49add4953c Fix docs typos (#871)
Fixes #869
Fixes #870

[ci skip]
2018-03-05 16:32:39 -08:00
Larry Gritz 75012eb38e docdeep 2018-03-05 15:06:54 -08:00
Larry Gritz 634c1d30d8 Improve oslc error reporting (#867)
For many grammatical constructs, the "source line" recorded in the AST
node is where the grammatical case ENDS. As an example,

    1:  shader foo (int holdout
    2:                    =
    3:                    1)
    4:  { }

There is a warning because 'holdout' masks another symbol at the same
scope. You would think the warning should be reported as occurring on
line 1, but it is reported for line 3, because that's where the clause
ends.

This will tend to happen for grammatical constructs that look like

     ANCHOR potentially-long-expression-that-may-span-lines

where any sensible person would want the warning associated this to be
on the line of the anchor, not wherever the long expression happens to
end.

In this patch, I carefully fix a whole lot of these grammatical
constructs to patch the 'sourceline' of the AST node they create with
the line that a particular anchor symbol is on.

There's a bit of extra work for ASTvariable_declaration, because there
are some errors (for duplicate symbols, etc.) that happen in the
constructor itself, so it's too late to return from the constructor and
then reset the source line; the misleading error has already been
issued.  So in that case, I added a line override parameter to the ctr
itself, mimicking the solution I implemented some time back for a
similar situation with function declarations.
2018-03-05 09:44:08 -08:00
Larry Gritz 803713303a SPI changes to find Cuda and OptiX 2018-02-27 13:36:52 -08:00
timgrant 89faf72cd0 OptiX integration (#861)
First checkin of effort to make OSL for OptiX/Cuda.

* Add (optional) OptiX and CUDA dependencies to the build system. None of this comes into play unless you build with the optional USE_OPTIX=1

* Add testoptix project to verify basic OptiX functionality. This is similar in spirit to the existing "testrender", but using OptiX to do all the heavy lifting. It does not currently shade with OSL... just laying the groundwork for a test harness.

* Add testoptix to the testsuite.

* Use NVCC for offline PTX generation rather than using NVRTC. Use CUDA_TOOLKIT_ROOT_DIR instead of CUDAHOME in CMake build.
2018-02-27 13:35:17 -08:00
Larry Gritz eac82a0087 #pragma osl nowarn suppresses warning on the following source line. (#864)
This sets the precedent that all future osl pragmas will start with
`#pragma osl`, and that any other token after the `#pragma` will be
ignored.
2018-02-16 10:44:49 -08:00
Larry Gritz 020214b582 Warning fixes and general cleanup to recently added typecheck code (#863)
The most important change here is to modify the practice making
multi-line warnings/errors by issuing a warning/error for the first line
followed by message() calls for the subsequent line.  Instead, we
generate those line-by-line messages as strings, and at the very end
issue a single warning or error call.

Also, directly call m_compiler->warning or error, don't bypass the
compiler by calling the app's error handler.

The reason both of those are important is that I have a separate change
I am ready to submit that is about giving a `#pragma nowarn` that can be
used to suppress warnings on the following line. This is totally borked
by warnings that span multiple calls and where most of their output is
in the form of message() and thus aren't easily recognized as part of
the warning.

This includes some general stylistic cleanup also in a few spots, some
preferences I have but but did not feel was worth nit picking line by
line in the original PRs.
2018-02-15 16:19:09 -08:00
Christopher Kulla f19ab7ced8 Upgrade SPI makefiles to Clang 5.0.1 final 2018-02-15 08:25:14 -08:00
marsupial 0afc301019 C++11 style Initializer lists (#838)
This lets you have constructs like

    // pass a {} list as a triple, matrix, or struct
    void func (point p);
    func ({x, y, z});

    // Assign {} to a struct if the types match up
    struct vec2 { float x, y; };
    vec2 v = {a,b};
    
    // Compact 'return' notation, it knows to construct the return type
    vec2 func (float a, float b)
    {
        return {a, b};
    }

Along the way, a number of steps:

* Initialize struct array elements without going through a temporary.

* Refactor codegen of aassign into single method.

* Allow float <=> int conversions using "aassign" without going through a temporary.

* Allow initializer lists as return types.

* Allow initializer lists as function/constructor arguments.

* C++11 style initializer lists.

* Complete ASTcompound_initializer type check/binding.

* Remove ASTNode typecheck_initlist & typecheck_struct_initializers.
Everything now flows properly through ASTcompound_initializer.

* Adapt to recent function-overload changes.
Hide some implementation details that don't need to be public.

* Error on ambiguity of arguments using init-lists.

* Make warnings & errors involving initializer list arguments more obvious.
2018-02-14 23:05:01 -08:00
Larry Gritz db85b9af61 oslc -Werror (#862)
This flag to oslc will treat all warnings issued as if they were errors.
2018-02-14 11:18:33 -08:00
Chris Kulla b036b11055 Fix LLVM memory manager for LLVM 6.0 and higher
Refactor code to avoid unecessary casts
2018-02-14 09:40:34 -08:00
Chris Kulla 3fb1ca5eaf Add support for Clang 6.0.0rc2 in SPI makefiles 2018-02-14 09:40:34 -08:00
marsupial 15b8664336 Fix remaining undefined behavior from functions ambiguous by return type. (#858)
Adds color closures, structs, and void to the defined precedence order of resolving via return type.
Errors when disambiguating via return type and more than one user struct is a match.
2018-02-14 00:25:05 -08:00
Larry Gritz 8a3242c1d5 Tweak OIIO related deprecations (#859)
For some time, the current master had advertised that it requires OIIO
>= 1.8. This patch simplify code by removing #if clauses related to OIIO
versions older than that.
2018-02-13 15:39:13 -08:00
Larry Gritz b1ed8cc599 CHANGES 2018-02-11 15:51:54 -08:00
Larry Gritz a271bfc786 Shader parameter metadata [[ int allowconnect = 0 ]] (#857)
If a shader input parameter has this metadata present and set to
nonzero, no incoming connections via ConnectShaders() will be accepted,
resulting in a runtime error if it is attempted.
2018-02-07 14:03:14 -08:00
marsupial a157358717 Minor fixes to recent changes. (#856)
* Windows: Fix strcasecmp usage.
* Fix renamed test which got borked in merge.
2018-02-07 10:59:47 -08:00
marsupial 4d928f6623 Function redefinitions (#853)
* Error on redefinition of functions in same scope with matching signatures.

* Move function redefinition in same scope to back to a warning.

* Call ASTNode::warning with a fully formed string instead of piecemealing formatting.

* Swap order of scope and argument comparison to avoid unnecessary string comparisons.
2018-02-06 11:39:11 -08:00
marsupial 926e98b408 Fix poorly defined behavior when choosing certain function overloads. (#844)
For function overloading in ambiguous cases, we were (a) doing some weird things; and (b) had the resolution dependent on the order the functions were declared, which seems bad.

This set of changes introduces a new polymorphic ranking system that is better documented, consistent, and not declaration-order-dependent.

For now, if the OSL_LEGACY_FUNCTION_RESOLUTION env variable is set, it should revert to old behavior.

We also fix a bug where type casts (like `(vector)foo()`) would properly pass the desired type hint down to the type checking and selection of foo, but type constructors (like `vector(foo())`) would not. This was an error, and is now also fixed. This may change behavior in some cases.

Better ambiguity error messages overall.
2018-02-06 11:00:37 -08:00
marsupial 83159c81b9 Appveyor (#855)
* Appveyor: Fix FreeType discovery for building OIIO and testing OSL.

* Appveyor: Fix passing CMake wrong directory to OpenImageIO.
Always create the download directory and skip Appveyor’s test discovery step.
2018-02-06 09:53:15 -08:00
Larry Gritz 5a5766f85a Add missing info and message reporting methods to ASTNode and OSLCompileImp. (#854) 2018-02-05 13:48:05 -08:00
marsupial e410f16a05 Skip OSL tests on Appveyor when updating the dependency cache. (#852)
Always build OIIO from master instead of caching it.
Limit MSBuild output to interesting notes only.
2018-02-05 10:25:06 -08:00
Larry Gritz 4cc1f66294 Document changes to connection rules 2018-02-01 12:14:46 -08:00
Larry Gritz ca0738de90 CHANGES / docs 2018-02-01 12:00:16 -08:00
marsupial 2398438c0c Allow individual components of aggregate types to be connected. (#801)
Connecting only the r,g, or b channels into another color is common in a lot shader networks.

* Support connections between Symbol components.

* Add component connection tests.

* Debug aid: human readable Connection

* Avoid errors for component connections when optimizing.

* Remove init ops for any fully connected destination param.
2018-02-01 11:59:21 -08:00
Larry Gritz 7a0f6c3ddc Force -Wall on Travis builds (#850) 2018-02-01 11:11:58 -08:00
Larry Gritz 778624d9fb Appveyor: tweak which branches will run, run tests with --output-on-failure 2018-01-31 13:39:43 -08:00
Frederich Munch e99fad5c45 Appveyor 2018-01-30 17:01:32 -08:00
Frederich Munch 62c1c3da0c CMake: Fix LLVM_SYSTEM_LIBRARIES on Windows. 2018-01-30 17:01:32 -08:00
Frederich Munch 6074cd0347 Fix problems running test suite on Windows. 2018-01-30 17:01:32 -08:00
Frederich Munch b0a680ff4e Add Windows export for liboslnoise. 2018-01-30 17:01:32 -08:00
Frederich Munch caef3c954a Work around boost::wave’s preprocessing escaping Windows path separators. 2018-01-30 17:01:32 -08:00
Frederich Munch 320e82ab37 Fix bug/undefined behavior trying to format/printf a struct value. 2018-01-30 17:01:32 -08:00
marsupial cf58c7343d Minor fixes - boost::wave whitespace issue and uninitialized variable (#840)
* Turn off Turn off whitespace insertion when using boost::wave.

* Fix  un-initialized members of ASTfunction_call.
Move all initialization into constructor so some compilers can error on regression.
2018-01-30 15:46:44 -08:00
Larry Gritz c505420eb6 Improve install instructions 2018-01-29 23:20:31 -08:00
Larry Gritz b4c8d2850f Fix compiler warning about possibly uninitialized variable (false positive) (#847)
Fixes #846
2018-01-25 16:29:18 -08:00
Larry Gritz ca0c6df4e0 Fix slightly broken overload resolution (#845) 2018-01-23 14:27:53 -08:00
Larry Gritz 967960dc54 Revert "Fix poorly defined behavior when choosing certain function overloads. (#837)"
This reverts commit 597b6b17e2.
2018-01-20 14:47:29 -08:00
Larry Gritz 2e2e2feb7c oslc: Add warning for detection of duplicate functions in the same scope. (#746)
Previously, if you for some reason defined two identical functions in
the same scope (including redefining a "built-in" function exactly in
the outermost scope), it would just silently accept it, and then you
wouldn't be sure which one would actually end up getting called.

For now it's a warning. After people have had a chance to scrub their
code bases, perhaps we will upgrade this to a full error in a future
release.
2018-01-18 13:56:41 -08:00
Larry Gritz d0f158a7cd Docs: Clarify function overloading 2018-01-17 10:51:17 -08:00
marsupial 597b6b17e2 Fix poorly defined behavior when choosing certain function overloads. (#837)
Previously the order of overload declarations would affect which was chosen.

This attempts to define how overloads are chosen in a more concrete way by scoring:

1. all arguments match without conversion
2. prefer promotion of int -> float over float -> int
3. use return type to resolve any possible ambiguities
2018-01-17 10:04:26 -08:00
Larry Gritz b52b3e673d docdeep (#842)
Why write documentation when you could make yet another documentation
generator?

I like the *idea* of Doxygen -- generate documentation by extracting the
comments in code, particularly those explaining the individual functions
or methods that are part of an API. But Doxygen, ick. Its markup
conventions make the code comments themselves hard to read, and the
output HTML is...  not very aesthetically pleasing (to me, at
least). And it's really a kitchen sink package, a lot of baggage to
carry along for the 2% of it that I really want.

On the other hand, I just love Morgan McGuire's awesome Markdeep
package (https://casual-effects.com/markdeep/), which is an extension
of Markdown but adds a crap ton of neato features that are great for
code, math, and diagrams.

So I tried my hand at doing something really small and "good enough" to
let you mark up your code comments -- but MINIMALLY, so subtly that the
casual observer might not even notice, and using markdeep for anything
fancy -- and then extract that material to generate Markdeep-based
documentation pages that look beautiful.

So here is the prototype. The entire implementation is just one Python
script, src/build-scripts/docdeep. In addition to documenting itself,
I also used oslquery.h to test the idea, so you can see both how the
docdeep markup looks in code, and as well, now we finally have OSLQuery
class documentation, which we never had before. Ha! Those two pieces
of documentation are generated automatically as part of the OSL build, so
you can see what we did on the CMake side to make that happen.

To see how you use it in source, look at oslquery.h.
(Better to just look at the new oslquery in toto, rather than trying to
understand just the diffs of this patch.)

To see what the resulting docs look like, build OSL and look at the
resulting share/doc/OSL/OSLQuery.md.html in your browser.

This is still experimental. I expect it to undergo a lot of revision.
When it settles down, if this looks useful to people and there is
demand, I might split this off into a separate open source project (just
the docdeep script) so that people can use it for other projects without
the overhead of downloading and building OSL. Let's see how it goes.

Feedback appreciated.
2018-01-16 12:39:59 -08:00
Alexis Oblet 714db4adb7 oslc: handle args if the shader file is not the last argument (#841) 2018-01-13 17:17:44 -08:00
Larry Gritz 75461a12ae Change URL for LLVM source after it moved 2018-01-12 19:11:51 -08:00
marsupial df98828efd Fix oslc crash with invalid field selection. (#835) 2017-12-19 00:47:15 -08:00
Larry Gritz cb9935cdf5 Fixes to group names and debug bitcode output (#833)
* Better guaranteed unique naming of missing names.

* When dumping ll/bc files for debugging to filenames derived from the
  group name, beware group names that have slashes in them! Also,
  sheesh, watch out for group names that are so long that they exceed
  the longest filename allowed (256 chars for most modern filesystems).

* Decided only the ll files are useful for debugging, I don't think we
  need the binary bc files.

* Simplify ShaderGroup ctr by using C++11 data member defaults and
  delegating constructors.
2017-12-12 10:19:41 -08:00
Larry Gritz 0729cca05b Adjust deprecations (#832)
Remove a method that has been deprecated since OSL 1.6, and mark some
methods that were deprecated since 1.8 with the OSL_DEPRECATED warning.
2017-12-08 21:06:12 -08:00
Larry Gritz 5f99b5c93d Enable symbols in the JIT for the Intel Vtune profiler (#830)
* Enable helpful symbols in the JIT for Intel Vtune profiler

* Bump which compiler SPI uses
2017-12-08 14:22:39 -08:00
Larry Gritz 5fe0c5bd9a Some bitcode and symbol debugging aids (#831)
* Add a new shadingsys option "llvm_optput_bitcode" that will dump the
bitcode for each group, even if the other debug options aren't turned all
the way on.

* bitcode now dumps in text as well as binary. (It saves a step of running
"llvm-dis" if your goal is just ot see the text in the first place, and also
it helps the llvm bug where sometimes it refuses to work because of mismatched
version strings.)

* Make sure that both in the bitcode output and other debug symbols,
we are more careful about being sure the shader group name is included,
not just the layer name, and also if a layer name is not specified to
ss->Shader(), make one up based on the shader master name and the
layer number.
2017-12-08 13:17:32 -08:00
Chris Kulla 5ea1cceb8c Pass the context's texture_thread_info to the render services texture callbacks instead of always passing NULL 2017-12-06 09:54:38 -08:00
Larry Gritz cd6081e609 CHANGES 2017-12-04 22:30:45 -08:00
Larry Gritz 7f9372f7a2 osltoy (#824)
osltoy is a GUI app that lets you interactively edit a pattern shader
and adjust its parameters, seeing the updated rendered results in
real time.

It's the OSL equivalent https://www.shadertoy.com/

The GUI uses Qt5. If that's not on your system (or if you purposely
disable it with the build-time option USE_QT=0), osltoy will not be
built (but the rest of OSL will).

A few other changes that come along with the ride:

* The `shade_image` utility function has changed its API slightly: the
  last (optional) parameter that used to be a simple thread count is now
  a `parallel_image_options` struct. But this struct can be implicitly
  constructed from an int (which is, in fact, the thread count), so any
  source code that calls shade_image should not need to be altered.

* New mandelbrot.osl shader has been added. It computes Julia sets, too.
  Enjoy!
2017-12-04 15:09:17 -08:00
Larry Gritz 897c20dce6 Add missing OSLQuery::Parameter correct assignment operator (#827) 2017-12-01 14:46:37 -08:00
Mark Final 416d443f82 Fixes compiler error (AppleClang,Gcc) in using std::atomic values as printf arguments (#826)
Compiler error in AppleClang (Xcode8) is

/Users/mark/dev/Thirdparty/OSL-1.9/src/liboslcomp/ast.cpp:76:33: error: call to implicitly-deleted copy constructor of 'std::atomic<int>'
                             i, node_counts[i], node_counts_peak[i]);
                                ^~~~~~~~~~~~~~

Compiler error in Gcc (4.8) is

/home/mark/dev/Thirdparty/OSL-1.9/src/liboslcomp/ast.cpp:76:68: error: use of deleted function ‘std::atomic<int>::atomic(const std::atomic<int>&)’
                              i, node_counts[i], node_counts_peak[i]);
                                                                    ^
Believe this is a problem because printf accepts arguments by value, whereas OIIO 1.8's Strutil::printf takes by reference, and you can't copy a std::atomic.
2017-12-01 11:43:20 -08:00
Larry Gritz 848aa8e6d7 Update Markdeep version and break our style add-ons into separate docs.css. 2017-11-28 15:48:47 -08:00
Larry Gritz 18c3a0c620 Bump minimum OIIO dependency to 1.8 (master only) (#817) 2017-11-27 21:11:01 -08:00
Mark Final d27879a7db Fix to compile OSL debug against OIIO-1.7.x. Previously assumed OIIO 1.8 going by required headers and the new Strutil::printf function (#822) 2017-11-27 16:44:53 -08:00
Larry Gritz bd28ff18c5 OSLQuery improvements (#821)
* OSLQuery::Parameter -- add copy/move constructors

* Make the ShadingSystem side of OSLQuery correctly report default vals.
2017-11-27 16:44:01 -08:00
Mark Final 84e9205b5e VisualStudio 2015 x64 compilation fixes for 1.9.x (#820)
* VisualStudio 2015 x64 build fix

include/OSL/dual.h(64): error C2476: 'constexpr' constructor does not
initialize all members

According to http://en.cppreference.com/w/cpp/language/constexpr, this
is an expected error for C++11, but not for C++14 and beyond.

* VisualStudio 2015 x64 build fix

Using SimplePool in the member variables in ShadingContext is causing an
'attempting to reference a deleted function' error for the
std::unique_ptr<char>s.

Applying the rule of 5, to disallow copying or moving a SimplePool.
2017-11-26 21:18:41 -08:00
Larry Gritz 61bb74ee65 Trim verbose build output of clutter 2017-11-16 17:36:08 -08:00
Brecht Van Lommel 01167e2a73 Fix ClosureComponent to work with SSE alignment requirements. (#810) 2017-11-16 14:33:06 -08:00
Larry Gritz 1bd2d67d88 FindPugiXML.cmake touchup -- make robust to re-builds (#814)
Without this, certain build-change cmake-rebuild cycles could give
cmake errors instead of correctly re-finding the pugi files.
2017-11-16 13:23:57 -08:00
Larry Gritz f1ae57c75f ShadingSys option "allow_shader_replacement" (#816)
Default is 0, for old behavior in which it's an error for
LoadMemoryCompiledShader to try to load the same named shader more than
once.

If set to nonzero, this is allowed, replacing the old shader master.
This does not change any already declared shader groups, which
will continue to use the original definition at the time of their
declaration. But subsequent groups that reference the master will get
the latest one.
2017-11-16 12:37:30 -08:00
Larry Gritz 3bf2494b28 Allow stats to print if shaders were declared, even if not requested (#815) 2017-11-16 12:05:43 -08:00
Larry Gritz 43445591e4 oslc internals: Police up some uses of stderr -- use the error handler (#813)
Doesn't matter much from the command line, but when compiling in memory
with OSLCompiler, you don't want the errors leaking into stderr.
2017-11-16 10:16:46 -08:00
Larry Gritz 9568e93d59 whitespace 2017-11-15 16:10:12 -08:00
Larry Gritz 0647312733 oslc: Fix param write analysis bug for token/value optional arguments (#812)
Functions that take optional argument lists in token/value form, like
`texture` or `pointcloud_search` needed to mark just those value
references as "writeable" that are (for example, the one following
"alpha" for texture calls, but all of the optional value slots for
pointcloud_search).

The logic on the oslc side here was broken -- it worked when the token
was a string literal, but when it was a variable whose value wouldn't be
known until runtime, it was failing to mark it as writeable, whereas the
correct thing to do is to conservatively conclude that it *might* be
written to (we don't know yet) and mark it as such.

The cascade of errors could lead to incorrect runtime optimization, if
the only used output of the function call was one of these parameters
that failed to be marked as an output, so so the whole function call
might be subject to the "useless op elision" optimization wherein ops
whose writes are never subsequently read can be eliminated entirely.
2017-11-15 13:18:27 -08:00
Larry Gritz c3d062b0ca Bump LLVM minimum from 3.5 to 3.9. (#806)
This cleans up a lot of #if cases where we were trying to support a very
wide range of LLVM releases in the face of changing APIs. With 3.5 gone,
so too is the "old" JIT (it's all MCJIT now).

By the time we get around to the next major release, we may further
reduce the complexity by dropping support for 3.9 (i.e., minimum LLVM >=
4.0), but I'll leave that for a later review.

Also tweak the Travis settings to assure we test against all the supported
LLVM releases.
2017-11-14 11:10:35 -08:00
Larry Gritz 9c83485a4a Travis reduce package install cost
1. Instead of installing libboost1.55-all-dev, which truly is everything
boost, just install the boost headers and the library components for the
very small number of non-header things we want.

2. Move the Linux package installation to be per-matrix-entry, this
allows us to customize by only installing the specific g++ version we
need, and exclude some boost components (using gcc >= 4.9 removes the
need for boost regex, for example).

This shaves several MINUTES of time from each test matrix entry, which
had been needlessly downloading and installing unneeded packages.
2017-11-10 00:07:11 -08:00
Larry Gritz d541d1a113 pugi tweak 2017-11-10 00:06:15 -08:00
Larry Gritz 0d058c798e Simplify the PugiXML logic. (#809)
By default, look for a system install. If that's not found, check
the OIIO distribution, where another header-only copy can also usually
be found. Eliminate the USE_EXTERNAL_PUGIXML, I don't think anybody
depends on that as long as the default is to check system libs first.

The only thing this doesn't do well is to have a system PugiXML but
*force* us to use the one from OIIO (whose only possible advantage is that
it's namespaced). If this is a problem in practice, we can return to make
that possible.
2017-11-09 22:19:56 -08:00
Larry Gritz 86af7c880f Restore support for OIIO 1.7 (#808) 2017-11-09 17:05:53 -08:00
Larry Gritz 99b0db748e Suppress gcc7 warning about signed vs unsigned compare. (#807)
We can't fix the code -- it's not "our" code, it it's the stuff
generated as part of the build process by flex itself. The expedient
thing is to just suppress the warning in the flex-generated module.
2017-11-09 14:55:03 -08:00
Larry Gritz dcb810a109 Fix incorrect Linux pre-build LLVM for 4.0, 5.0 2017-11-02 10:54:44 -07:00
Larry Gritz 03b10d0d66 Bump version numbers after branch of OSL 1.9 2017-10-30 14:01:36 -07:00
653 changed files with 24076 additions and 6845 deletions
+148 -56
View File
@@ -1,27 +1,27 @@
# .travis.yml for OSL
language: cpp
sudo: false
osx_image: xcode7.3
osx_image: xcode10
dist: trusty
# Add-ons: specify apt packages for Linux
addons:
apt:
sources:
- boost-latest
- ubuntu-toolchain-r-test
- george-edison55-precise-backports
packages:
- cmake
- cmake-data
- g++-4.8
- g++-5
- g++-6
- g++-7
- libboost1.55-all-dev
- libtiff4-dev
# Currently, we do this per-matrix-entry so it can be finely customized
# so that each entry only get the packages it needs.
#addons:
# apt:
# sources:
# - ubuntu-toolchain-r-test
# packages:
# - g++-4.8
# - g++-6
# - g++-7
# - libboost-filesystem1.55
# - libboost-python1.55
# - libboost-regex1.55
# - libboost-system1.55
# - libboost-thread1.55
# - libboost-wave1.55
cache:
ccache: true
@@ -55,24 +55,32 @@ install:
src/build-scripts/install_homebrew_deps.bash ;
elif [ $TRAVIS_OS_NAME == linux ] ; then
CXX="ccache $CXX" CCACHE_CPP2=1 src/build-scripts/build_openexr.bash ;
export ILMBASE_HOME=$PWD/openexr-install ;
export OPENEXR_HOME=$PWD/openexr-install ;
if [ "$LLVM_VERSION" == "" ]; then export LLVM_VERSION="3.9.0" ; fi ;
wget http://releases.llvm.org/${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-14.04.tar.xz ;
tar xf clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-14.04.tar.xz ;
rm -f clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-14.04.tar.xz ;
export ILMBASE_ROOT_DIR=$PWD/ext/openexr-install ;
export OPENEXR_ROOT_DIR=$PWD/ext/openexr-install ;
export ILMBASE_HOME=$PWD/ext/openexr-install ;
export OPENEXR_HOME=$PWD/ext/openexr-install ;
if [ "$LLVM_VERSION" == "" ]; then export LLVM_VERSION="error" ; fi ;
if [ "$LLVM_VERSION" == "5.0.0" ]; then export LLVMTAR=clang+llvm-${LLVM_VERSION}-linux-x86_64-ubuntu14.04.tar.xz ; else export LLVMTAR=clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-14.04.tar.xz ; fi;
echo LLVMTAR = $LLVMTAR ;
wget http://releases.llvm.org/${LLVM_VERSION}/${LLVMTAR} ;
tar xf $LLVMTAR ;
rm -f $LLVMTAR ;
echo "Installed ${LLVM_VERSION}" ;
mv clang+llvm* llvm-install ;
export LLVM_DIRECTORY=$PWD/llvm-install ;
ls -a $LLVM_DIRECTORY ;
fi
# Note: can remove the ILMBASE_HOME/OPENEXR_HOME when OIIO 2.x is floor
- export OIIOMAKEFLAGS="$OIIOMAKEFLAGS -j2 DEBUG= USE_PYTHON=0 OIIO_BUILD_TESTS=0"
- export OPENIMAGEIO_SITE=travis
- export OSL_SITE=travis
- src/build-scripts/build_openimageio.bash
- export OPENIMAGEIOHOME=$PWD/OpenImageIO/dist/$OIIOPLATFORM
- export PATH=$OPENIMAGEIOHOME/bin:$PATH
- export DYLD_LIBRARY_PATH=$OPENIMAGEIOHOME/lib:$DYLD_LIBRARY_PATH
- export LD_LIBRARY_PATH=$OPENIMAGEIOHOME/lib:$LD_LIBRARY_PATH
- export PYTHONPATH=$OPENIMAGEIOHOME/python:$PYTHONPATH
- export OPENIMAGEIO_ROOT_DIR=$PWD/OpenImageIO/dist/$OIIOPLATFORM
- export OPENIMAGEIOHOME=$OPENIMAGEIO_ROOT_DIR
- export PATH=$OPENIMAGEIO_ROOT_DIR/bin:$PATH
- export DYLD_LIBRARY_PATH=$OPENIMAGEIO_ROOT_DIR/lib:$DYLD_LIBRARY_PATH
- export LD_LIBRARY_PATH=$OPENIMAGEIO_ROOT_DIR/lib:$LD_LIBRARY_PATH
- export PYTHONPATH=$OPENIMAGEIO_ROOT_DIR/python:$PYTHONPATH
- if [ $TRAVIS_OS_NAME == linux ] ; then
export BUILD_FLAGS="$BUILD_FLAGS LLVM_STATIC=1" ;
export TEST_FLAGS="-E broken\|render-cornell\|render-oren-nayar\|render-veachmis\|render-ward" ;
@@ -85,8 +93,8 @@ script:
- make VERBOSE=1 $BUILD_FLAGS cmakesetup
- make -j2 $BUILD_FLAGS
- export LSAN_OPTIONS=suppressions=$PWD/src/build-scripts/nosanitize.txt
- export OSLHOME=$PWD/dist/$PLATFORM
- export OIIO_LIBRARY_PATH=$OSLHOME/lib:${OIIO_LIBRARY_PATH}
- export OSL_ROOT_DIR=$PWD/dist/$PLATFORM
- export OIIO_LIBRARY_PATH=${OSL_ROOT_DIR}/lib:${OIIO_LIBRARY_PATH}
- make $BUILD_FLAGS test
@@ -105,40 +113,124 @@ branches:
matrix:
fast_finish: true
include:
# Build with C++11, default compiler, optimized build, against OIIO master
- os: linux
- name: "VFX Platform 2018 (gcc6, c++14), llvm 7, OIIO master, avx/f16c"
os: linux
compiler: gcc
- os: osx
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
- libboost1.55-dev
- libboost-filesystem1.55
- libboost-python1.55
- libboost-system1.55
- libboost-thread1.55
- libboost-wave1.55
env: WHICHGCC=6 USE_CPP=14 LLVM_VERSION=7.0.0 OIIOBRANCH=master USE_SIMD=avx,f16c
- name: "MacOS (latest Apple clang, llvm 7, OIIO master, latest homebrew libs"
os: osx
compiler: clang
# Test against the older release branch of OIIO (all the other tests
# are against OIIO master).
- os: linux
- name: "VFX Platform 2017 (gcc48, c++11), llvm 6, OIIO release, sse4.2"
os: linux
compiler: gcc
env: OIIOBRANCH=release
# Test gcc 5, also against higher SSE level
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libboost1.55-dev
- libboost-filesystem1.55
- libboost-python1.55
- libboost-regex1.55
- libboost-system1.55
- libboost-thread1.55
- libboost-wave1.55
env: WHICHGCC=4.8 USE_CPP=11 LLVM_VERSION=6.0.1 USE_SIMD=sse4.2 OIIOBRANCH=release
- name: "Older things: release OIIO, llvm 5, OIIO 1.8/oldest, boost 1.55"
os: linux
compiler: gcc
env: WHICHGCC=5 USE_SIMD=sse4.2
# Test gcc6, and highest SIMD level supported by Travis.
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libboost1.55-dev
- libboost-filesystem1.55
- libboost-python1.55
- libboost-regex1.55
- libboost-system1.55
- libboost-thread1.55
- libboost-wave1.55
env: WHICHGCC=4.8 USE_CPP=11 LLVM_VERSION=5.0.0 USE_SIMD=sse4.2 OIIOBRANCH=RB-1.9
if: branch =~ /(master|RB|travis)/ OR type = pull_request
- name: "gcc7, llvm7, C++14"
os: linux
compiler: gcc
env: WHICHGCC=6 USE_SIMD=avx,f16c
# Linux only: test gcc 7, also test C++14
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
- libboost1.55-dev
- libboost-filesystem1.55
- libboost-python1.55
- libboost-system1.55
- libboost-thread1.55
- libboost-wave1.55
env: WHICHGCC=7 USE_CPP=14 LLVM_VERSION=7.0.0
if: branch =~ /(master|RB|travis)/ OR type = pull_request
- name: "Future: gcc8, C++14, LLVM 7, OIIO master, AVX/f16c"
os: linux
compiler: gcc
env: WHICHGCC=7 USE_CPP=14
# Build with C++11, DEBUG build, against OIIO master
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
- libboost1.55-dev
- libboost-filesystem1.55
- libboost-python1.55
- libboost-system1.55
- libboost-thread1.55
- libboost-wave1.55
env: WHICHGCC=8 USE_CPP=14 LLVM_VERSION=7.0.0 USE_SIMD=avx,f16c
- name: "DEBUG build, LLVM 7, OIIO master"
os: linux
compiler: gcc
env: DEBUG=1
# Test against older LLVM
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libboost1.55-dev
- libboost-filesystem1.55
- libboost-python1.55
- libboost-regex1.55
- libboost-system1.55
- libboost-thread1.55
- libboost-wave1.55
env: DEBUG=1 LLVM_VERSION=7.0.0 OIIOBRANCH=master
- name: "Oldest everything: LLVM 4, OIIO 1.8, no simd"
os: linux
compiler: gcc
env: LLVM_VERSION=3.5.2
# One more, just for the heck of it, turn all SIMD off.
- os: linux
compiler: gcc
env: USE_SIMD=0
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libboost1.55-dev
- libboost-filesystem1.55
- libboost-python1.55
- libboost-regex1.55
- libboost-system1.55
- libboost-thread1.55
- libboost-wave1.55
env: USE_SIMD=0 LLVM_VERSION=4.0.0 OIIOBRANCH=RB-1.8
if: branch =~ /(master|RB|travis)/ OR type = pull_request
notifications:
email:
+408 -15
View File
@@ -1,11 +1,378 @@
Release 1.9 -- ?? 2017 (compared to 1.8)
Release 1.10.6 -- Jul 4, 2019 (compared to 1.10.5)
--------------------------------------------------
* Build: Fixes to FindOpenEXR.cmake. #1022
* ShadingSystem: when building a shader group from serialized commands,
respect the global lockgeom default. #1032
Release 1.10.5 -- May 1, 2019 (compared to 1.10.4)
--------------------------------------------------
* Extend linearstep() and smooth_linearstep() to work with color, point,
vector, and normal types (previously restricted to float). #994
* Improve oslc type error detection for variable declarations with init
expressions. Note that this may flag some warnings and errors that went
undetected before, involving initialization assignments of incompatible
types. #991, #993
* Add a build-time option GLIBCXX_USE_CXX11_ABI to force the "new/old string
ABI" to something other than the default for your version of gcc. #995
Release 1.10.4 -- Apr 1, 2019 (compared to 1.10.3)
--------------------------------------------------
* LPEs: forbid LPE repetitions inside groups. #972
* Build process: build script finding of LLVM is now more robust to certain
library configurations of llvm, particularly where everything is bundled
in just one libLLVM without a separate libLLVMMCJIT. #976
* oslc: Improve warnings about ill-advised use of the comma operator. #978
* oslc: Fix an assertion/crash when passing initialization-lists as
parameters to a function, where the function argument expected was as
array. #983
* oslc: Fix an assertion/crash for certain type constructors of structs,
where the struct name was not declared. (This is an incorrect shader,
but of course should have issued an error, not crashed.) #988
* Note: The experimental OptiX path is not expected to work in this branch!
Development has continued in the 'master' branch. If you are interested in
testing the OptiX support while it's under development, please do so with
the master branch, because fixes and improvements to the OptiX support
are not being backported to the 1.10 branch.
* Tested and verified that everything builds and works correctly with
Clang 8 and LLVM 8.0.
Release 1.10.3 -- Feb 1, 2019 (compared to 1.10.2)
--------------------------------------------------
* oslc: Writing to function parameters not marked as `output` was only
recently properly recognized as an error (it was documented as illegal
all along). Now we demote to a warning, treating it as a full error was
too disruptive. #944 (1.10.3)
* testshade: Check that no leftover errors are in the TextureSystem or
ImageCache at the end of the test (that would indicate that someplace in
OSL we are failing to check texture errors). #939 (1.10.3)
* Improve oso output efficiency. #938 (1.10.3)
* oslc: Fix bug related to counting the proper number of values used for
array default value initialization. #948 (1.10.3)
* oslc: Slight modification to the formatting of floating point values in
the oso file to ensure full precision preservation for float values.
#949 (1.10.3)
* oslc: Fix crash when encountering empty-expression `for (;;)`. #951 (1.10.3)
* oslc: Fix bug in code generation of certain `while` loops that directly
tested a variable as a zero/nonzero test, such as:
```
i = 3;
while (i)
--i;
```
whereas the following had worked (they should have been identical):
```
i = 3;
while (i != 0)
--i;
```
#947 (1.10.3/1.11.0)
* Fix bug in implementation of `splineinverse()` when computing with
Bezier interpolation. #954 (1.10.3)
* Fix bug in implementation of `transformc` when relyin on OpenColorIO for
color transformation math, in cases were derivatives were needed (this
is a rare case probably nobody ran into). #960 (1.10.3)
* Improve thread-safety of the OSLCompiler itself, in case an app wants
to be compiling several shaders to oso concurrently by different threads.
#953 (1.10.3)
Release 1.10 -- Dec 1, 2018 (compared to 1.9)
--------------------------------------------------
Dependency and standards changes:
* **LLVM 4.0 / 5.0 / 6.0 / 7.0**: Support has been removed for LLVM 3.x,
added for 6.0 and 7.0.
* **OpenImageIO 1.8/2.0+**: This release of OSL should build properly against
OIIO 1.8 or 2.0. Support has been dropped for OIIO 1.7.
New back-end targets:
* **OptiX** Work in progress: Experimental back end for NVIDIA OptiX GPU ray
tracing toolkit. #861, #877, #902
- Build with `USE_OPTIX=1`
- Requires OptiX 5.1+, Cuda 8.0+, OpenImageIO 1.8.10+, LLVM >= 5.0 with
PTX target enabled.
- New utility **testoptix** is an example of a simple OptiX renderer
that uses OSL for shaders.
- Work is in progress to support the majority of OSL, but right now it
is restricted to a subset. All the basic math, most of the
standard library, noise functions, strings (aside from if you create
entirely new strings in the middle of a shader), and closures work.
The biggest thing not working yet is textures, but those are coming
soon.
New tools:
* **osltoy** : GUI tool for interactive shader editing and pattern
visualization (somewhat in the style of [Shadertoy](http://shadertoy.com).
#827, #914, #918, #926 (1.10.0)
* **docdeep** : This Python script (in src/build-scripts/docdeep.py) is an
experimental tool to scrape comments from code and turn them into
beautiful Markdeep documentation. (A little like a VERY poor man's
Doxygen, but markdeep!) Experimental, caveat emptor. #842 (1.10.0)
OSL Language and oslc compiler:
* In OSL source code, we now encourage the use of the generic "shader" type
for all shaders, and it is no longer necessary or encouraged to mark
the OSL shader with a specific type, "surface", "displacement", etc.
From a source code and/or `oslc` perspective, all shaders are the same
generic type. A renderer may, however, have different "uses" or "contexts"
and may additional runtime perform error checking to ensure that the
shader group you have supplied for a particular "use" does not do things
or access globals that are not allowed for that use. #899
* C++11 style Initializer lists. (#838) This lets you have constructs like
// pass a {} list as a triple, matrix, or struct
void func (point p);
func ({x, y, z});
// Assign {} to a struct if the types match up
struct vec2 { float x, y; };
vec2 v = {a,b};
// Compact 'return' notation, it knows to construct the return type
vec2 func (float a, float b)
{
return {a, b};
}
* osl now warns when it detects duplicate declarations of functions with
the exact same argument list, in the same scope. #746
* osl now correctly reports the error when you write to a user-function
parameter that was not declared as `output` (function params are by
default read-only, but a shortcoming in oslc has prevented that error
from being issued). #878 (1.10.0)
* Fix oslc crash with invalid field selection syntax. #835 (1.10.0/1.9.6)
* oslc fix to properly handle command line arguments if the shader file is
not the last argument on the command line. #841 (1.10.0/1.9.7)
* oslc: when using boost.wave for preprocessing, fix whitespace insertion
#840 and windows path separators #849. #841 (1.10.0/1.9.7)
* oslc: Fix bug/undefined behavior when trying to format/printf a struct.
#849 #841 (1.10.0/1.9.7)
* New rules for how polymorphic function variants are chosen: Matches are
now ranked in an objective way that no longer depends on declaration
order. Type coercions are preferred in the following order of descending
score: exact match, int -> float, float -> triple, spatial triple ->
spatial triple, any triple -> triple. If there is a tie for passed
arguments, return types will break the tie. If there is still a tie or
truly ambiguous case, a warning will be printed explaining the choices and
which was chosen. #844 (1.10.0)
* It is now a warning to define the same function twice in the same scope.
#853 (1.10.0)
* A shader input parameter marked with metadata `[[ int allowconnect = 0 ]]`
will disallow runtime connections via `ConnectShaders()`, resulting in an
error. #857 (1.10.0)
* oslc command-line argument `-Werror` will treat all warnings as hard
errors (failed compilation). #862 (1.10.0)
* `#pragma osl nowarn` will suppress any warnings arising from code on the
immediately following line of that source file. #864 (1.10.0)
* oslc error reporting is improved, many multi-line syntactic constructs
will report errors in a more intuitive, easy-to-understand line number.
#867 (1.10.0)
* Faster parsing of very large constant initializer lists for arrays in OSL.
We found an inadvertent O(n^2) behavior when parsing initializer lists.
It used to be that a constant table in the form an array of 64k floats
took over 10s to compile, now it is 50x faster. #901
* Resolution of ambiguous return type functions (such as noise) has been
improved when their results are used as arguments to type constructors.
#931 (1.10.1)
OSL Standard library:
* There has been a change in the appearance to Cell noise and Gabor noise.
This is to fix a bug that made an incorrect pattern for certain negative
exact-integer values for cellnoise, and in lots of places for Gabor noise.
The only way to fix it was to potentially change the appearance for some
shaders. Sorry. If this is a real problem, let us know, perhaps we can
make a build-time switch that will let you use the old buggy noise? But
since this is a "2.0" release, we figured it was as good a time as ever to
let it change to the correct results. #912 (1.10.0)
Shaders:
* Contributed shader library changes:
* mandelbrot.osl: computes Mandelbrot and Julia images. #827 (1.10.0)
* MaterialX support:
* Improved support for MaterialX 1.36: add sin, cos, tan, atan2, ceil,
sqrt, exp, determinent, ln, transpose, sign, rotate, transforms,
rgb/hsv convert, extract, separate, tiledimage. Rename exponent ->
power, pack -> combine, hsvadjust -> hueshift. Add some color2/4
mutual conversion operators. Fixes to ramp4, clean up texture mapping
nodes, fixes to triplanarprojection weighting. Extend add/sub/mul/div
to include matrices. #903, #904, #905, #907, #909 (1.9.10/1.10.0)
API changes, new options, new ShadingSystem features (for renderer writers):
* ShadingSystem API:
* It is now permitted to ConnectShaders a single component of a
color/point/vector/normal to a float and vice versa. #801 (1.10.0)
* An older version of ShadingSystem::execute, which had been marked
as deprecated since OSL 1.6, has been fully removed. #832 (1.10.0)
* `ShadingSystem::Shader()` now has all three parameters required (none
are optional), though the "use" parameter no longer has any meaning.
(It will be deprecated and removed in a future release.) #899
* `ShadingSystem::optimize_group()` now takes an optional pointer to a
`ShadingContext`, which it will use if needed (if passed NULL, one
will be internally allocated, used, and freed, as before). #936
* ShadingSystem attributes:
* New `"allow_shader_replacement"` (int) attribute, when nonzero, allows
shaders to be specified more than once, replacing their former
definitions. The default, 0, considers that an error, as it always
has. #816 (1.10.0).
* New developer option `"llvm_output_bitcode"` dumps the bitcode for each
group, even if other debug options aren't turned on, and also any
dumped bitcode will save as text as well as binary. #831 (1.10.0)
* New attribute `"error_repeats"`, if set to non-zero, turns off the
suppression of multiple identical errors and warnings. Setting it
(even to its existing value) also clears the "already seen" lists.
#880, #883 (1.10.0/1.9.9/1.8.14)
* Shader group attributes:
* New attributes that can be queried with `getattribute()`:
`"globals_read"` and `"globals_write"` retrieve an integer bitfield
that can reveal which "globals" may be read or written by the shader
group. The meaning of the bits is given by the enum class `SGBits`
in `oslexec.h`. #899
* RendererServices API:
* Older versions of RendererServices texture functions, the old ones
with no errormessage parameter, which were documented as deprecated
since 1.8, are now marked OSL_DEPRECATED. #832 (1.10.0)
* OSLCompiler API:
* Improved error reporting when compiling from memory buffer. The
`OSLCompiler::compile_buffer()` method now takes an optional filename
parameter that will make error messages attribute the right "file"
(e.g., `Error: foo.osl:5...` rather than `<buffer>:5...`). #937 (1.10.2)
* Miscellaneous:
* liboslnoise: Properly hide/export symbols. #849 (1.10.0/1.9.7)
* The behavior of the "searchpath:shader" attribute, used for finding
`.oso` files when shaders is requested, has been modified. If no
search path is specified, the current working directory (".") will
be searched. But if there is a search path attribute specified, only
those directories will be searched, with "." only searched if it is
explicitly included in the search path value. #925 (1.10.0)
Bug fixes and other improvements (internals):
* The context's `texture_thread_info` is now properly passed to the
RenderServices callbacks instead of passing NULL. (1.10.0)
* Symbols are enbled in the JIT, allowing Intel Vtune profiler to correctly
report which JITed OSL code is being executed. #830 (1.10.0)
* ASTNode and OSLCompilerImpl -- add info() and message() methods to
complement the existing error and warning. #854 (1.10.0)
* Fix incorrect array length on unbounded arrays specified by relaxed
parameter type checking. #900 (1.9.10/1.10.0)
* oslc bug fix: the `regex_search()`/`regex_match()` functions did not properly
mark their `results` output parameter as write-only. This was never
noticed by anyone, but could have resulted in incorrect optimizations.
#922 (1.10.0)
* When reading `.oso` files, the parser is now more robust for certain ways
that the oso file might be corrupted (it's more forgiving, fewer possible
ways for it to abort or assert). #923 (1.10.0)
* Bug fixes related to incorrect reliance on OIIO's `ustring::operator int()`.
It's being removed from OIIO, so wean ourselves off it. #929 (1.10.0)
* Certain texture3d lookups with derivatives could crash. #932 (1.10.1)
* Fix oslc assertion crash when a struct parameter was initialized with
a function call. #934 (1.10.1)
Build & test system improvements:
* Appveyor CI testing for Windows. #849,852,855 (1.10.0/1.9.7)
* Our new policy is to disable `STOP_ON_WARNING` for release branches, to
minimize build breaks for users when a new compiler warning is hit. We
still enable it in development/master branches as well as any CI build
in any branch. #850 (1.10.0/1.9.7)
* Testsuite is now Python 2/3 agnostic. #873 (1.10.0)
* Build the version into the shared library .so names. #876
(1.8.13/1.9.8/1.10.0)
* Update to fix with OpenImageIO 1.9. #882,#889
* Flex/bison fixes on Windows. #891
* Fix Windows build break with iso646.h macros. #892
* Fix warnings on gcc 6. #896
* Fix errors building with MSVC. #898
* Fixes to build with clang 7, and to use LLVM 7. #910, #921 (1.10.0)
* Fix warnings on gcc 8. #921 (1.10.0)
* Build system: the variables containing hints for where to find IlmBase
and OpenEXR have been changed to `ILMBASE_ROOT_DIR` and `OPENEXR_ROOT_DIR`
(no longer `ILMBASE_HOME`/`OPENEXR_HOME`). Similarly, `OPENIMAGEIO_ROOT_DIR`
is the hint for custom OIIO location (no longer OPENIMAGEIOHOME). #928
* Eliminated some in-progress MaterialX tests, they weren't in good order,
we will do it differently if we want to add MX tests in the future. #928
* Build options `OSL_BUILD_SHADERS` and `OSL_BUILD_MATERIALX` (both default
to ON) can be used to disable building of all shaders or MX shaders,
respectively. #935 (1.10.1)
Documentation:
* `osltoy` documentations in `doc/osltoy.md.html` (1.10.0).
Release 1.9.13 -- 1 Dec 2018 (compared to 1.9.12)
------------------------------------------------
* Fix crash with texture3d lookups with derivatives. #932
* Fix oslc crash when a struct parameter is initialized with a function call
that returns a structure. #934
Release 1.9.12 -- 1 Nov 2018 (compared to 1.9.11)
------------------------------------------------
* Fix oslc read/write error for `regex_search`/`regex_match` #922
* Make oso reading more robust to certain broken inputs. #923
* Internals: make safe for some changes coming to ustring API in OIIO
master. #929
* Several docs fixes.
Release 1.9.11 -- 1 Oct 2018 (compared to 1.9.10)
------------------------------------------------
* Full support for using LLVM 6.0 and 7.0. #913, #919
* Support for building with gcc 8. #921
* Fix testrender bug with undefined order of operations (only was a problem
with gcc5 and clang7). #916
Release 1.9.10 -- 1 Sep 2018 (compared to 1.9.9)
------------------------------------------------
* Fix Windows compile of the flex/bison compiler components. #891
* Fix for compatibility with OIIO 1.9.
* Fix incorrect array length on unbounded arrays specified by relaxed
parameter type checking. #900
* Speed up oslc parsing of long constant initializer lists. #901
* Add more functions to color2.h, color4.h, vector2.h, vector4.h: ceil,
sqrt, exp, log2, log, sign, sin, cos, tan, asin, acos, atan2. #903, #904
* Improved support for MaterialX 1.36: add sin, cos, tan, atan2, ceil, sqrt,
exp, determinent, ln, transpose, sign, rotate, transforms, rgb/hsv convert,
extract, separate, tiledimage. Rename exponent -> power, pack -> combine,
hsvadjust -> hueshift. Add some color2/4 mutual conversion operators.
Fixes to ramp4, clean up texture mapping nodes, fixes to triplanarprojection
weighting. Extend add/sub/muldiv to include matrices. #903, #904, #905
Release 1.9.9 -- 1 May 2018 (compared to 1.9.8)
-----------------------------------------------
* New SS attribute `"error_repeats"`, if set to non-zero, turns off the
suppression of multiple identical errors and warnings. Setting it (even to
its existing value) also clears the "already seen" lists. #880
(1.8.14/1.9.9)
* Update to fix with some changes in OpenImageIO 1.9. #882
Release 1.9.8 -- 1 Apr 2018 (compared to 1.9.7)
-----------------------------------------------
* Build the version into the shared library .so names. #876 (1.8.13/1.9.8)
Release 1.9.7 -- 1 Feb 2018 (compared to 1.9.6)
-----------------------------------------------
* oslc fix to properly handle command line arguments if the shader file is
not the last argument on the command line. #841
* oslc: when using boost.wave for preprocessing, fix whitespace insertion
#840 and windows path separators #849.
* oslc: Fix bug/undefined behavior when trying to format/printf a struct.
#849
* liboslnoise: Fix symbol export/hiding. #849
* Misc build issue cleanup on Windows. #849
* For release branches, we no longer have builds consider every compiler
warning to be an error (except in master or for CI builds).
Release 1.9.6 -- 1 Jan 2018 (compared to 1.9.5)
-----------------------------------------------
* Fix oslc crash with invalid field selection syntax. #835
* Certain texture calls were inadvertently not passing in thread data,
forcing the texture system to look it up again redundantly. #829
Release 1.9 -- 4 December 2017 (compared to 1.8)
--------------------------------------------------
Dependency and standards changes:
* **C++11 required**: OSL 1.9 requires a minimum standard of C++11. It
should also build against C++14 and C++17.
* **LLVM 3.5 / 3.9 / 4.0 / 5.0**: Support has been added for LLVM 3.9, 4.0, and
5.0. Support has been removed for for LLVM 3.4.
* **LLVM 3.5 / 3.9 / 4.0 / 5.0**: Support has been added for LLVM 3.9, 4.0,
and 5.0. Support has been removed for for LLVM 3.4.
* **OpenImageIO 1.7+**: This release of OSL should build properly against
OIIO 1.7 or newer. You may find that 1.6 is still ok, but we are not doing
any work to ensure that.
@@ -14,14 +381,14 @@ Dependency and standards changes:
* **OpenEXR/IlmBase >= 2.0** (recommended: 2.2)
Language features:
* New preprocessor symbols: OSL_VERSION_MAJOR, OSL_VERSION_MINOR,
OSL_VERSION_PATCH, and OSL_VERSION (e.g. 10900 for 1.9.0) reveal the
* New preprocessor symbols: `OSL_VERSION_MAJOR`, `OSL_VERSION_MINOR`,
`OSL_VERSION_PATCH`, and `OSL_VERSION` (e.g. 10900 for 1.9.0) reveal the
OSL release at shader compile time. #747 (1.9.0)
* Structure constructors: If you have a struct `S` comprising fields with
types T1, T2, ..., you may now have an expression `S(T1 v2,T2 v2,...)` that
constructs and returns an `S` with those field values, much in the same
way that you can say `color(a,b,c)` to construct a color out of components
a, b, c. #751 (1.9.0)
types T1, T2, ..., you may now have an expression `S(T1 v2, T2 v2,...)`
that constructs and returns an `S` with those field values, much in the
same way that you can say `color(a,b,c)` to construct a color out of
components a, b, c. #751 (1.9.0)
* User-defined operator overloading: If you make a new (struct) type, it
is possible to define overloaded operators, like this:
@@ -99,8 +466,8 @@ API changes, new options, new ShadingSystem features (for renderer writers):
parameters expecting a float-aggregate or array thereof, and an `int`
may be passed to a parameter expecting a `float`, and an `int[1]` may
be passed to an `int` parameter. #794,#797 (1.9.1)
* Shader group attribute additions/changes:
* RendererServices:
* Fixed `ClosureComponent` to work with SSE alignment requirements. #810
(1.9.3)
Performance improvements:
* Shader JIT time is improved by about 10% as a result of pre-declaring
@@ -163,6 +530,15 @@ Bug fixes and other improvements (internals):
the `'.'` (dot) character as decimal separator in floating point number,
even when running on a computer system configured to use a foreign locale
where the comma is traditionally used as the decimal separator. #795 (1.9.1)
* Fix param analysis bug for texture or pointcloud functions with optional
token/value parameters where the token name wasn't a string literal -- it
could fail to recognize that certain parameters would be written to by the
call. #812 (1.9.3)
* ShadingSystem statistics are now printed if any shaders were
declared/loaded, even if no shaders were executed. #815 (1.9.3)
* Minor OSLQuery implementation improvements: add move/copy constructors
for OSLQuery::Parameter, make the ShadingSystem side of OSLQuery correctly
report default parameter values. #821 (1.9.4)
Build & test system improvements:
* C++11 is the new language baseline. #704, #707
@@ -220,6 +596,11 @@ Build & test system improvements:
#788 (1.9.1)
* Improved proper rebuilding of the LLVM bitcode for llvm_ops.cpp when only
certain headers change. #802 (1.9.1)
* Fix gcc7 warnings about signed vs unsigned compares. #807 (1.9.2)
* Simplify the build logic for finding PugiXML and prefer a system install
when found, rather than looking to OIIO to supply it. #809 (1.9.2)
* MSVS 2015 x64 compilation fixes. #820 (1.9.4)
* Fix debug compile against OIIO 1.7. #822 (1.9.4)
Developer goodies:
* The `dual.h` implementation has been completely overhauled. The primary
@@ -237,6 +618,22 @@ Documentation:
* Full testshade docs in `doc/testshade.md.html` (1.9.0)
Release 1.8.15 -- 1 Aug 2018 (compared to 1.8.14)
--------------------------------------------------
* Fixes for compatibility with OIIO 1.9.
Release 1.8.14 -- 1 May 2018 (compared to 1.8.13)
--------------------------------------------------
* New SS attribute "error_repeats", if set to non-zero, turns off the
suppression of multiple identical errors and warnings. Setting it (even to
its existing value) also clears the "already seen" lists. #880
* Update to fix with some changes in OpenImageIO 1.9. #882
Release 1.8.13 -- 1 Apr 2018 (compared to 1.8.12)
--------------------------------------------------
* Build the version into the shared library .so names. #876
Release 1.8.12 -- 1 Nov 2017 (compared to 1.8.11)
--------------------------------------------------
* Improve type checking error messages with structs. #761
@@ -406,10 +803,6 @@ API changes, new options, new ShadingSystem features (for renderer writers):
* Attribute "llvm_debug_ops" adds a printf before running each op.
This is mostly for debugging OSL itself, not for users. (1.8.3)
<!--* Shader group attribute additions/changes:
* RendererServices:
-->
Performance improvements:
* New runtime optimization: better at understanding the initial values of
output parameters and what optimizations can be done based on that. #657
+66 -24
View File
@@ -1,13 +1,13 @@
cmake_minimum_required (VERSION 3.2.2)
cmake_policy (SET CMP0048 NEW) # Allow VERSION specifier in project()
project (OSL
VERSION 1.9.1
VERSION 1.10.6
LANGUAGES CXX C)
set (PROJ_NAME ${PROJECT_NAME}) # short name
string (TOLOWER ${PROJ_NAME} PROJ_NAME_LOWER) # short name lower case
set (PROJECT_VERSION_RELEASE_TYPE "dev") # "dev", "betaX", "RCY", ""
set (PROJECT_VERSION_RELEASE_TYPE "") # "dev", "betaX", "RCY", ""
set (${PROJECT_NAME}_VERSION_RELEASE_TYPE ${PROJECT_VERSION_RELEASE_TYPE})
set (PROJECT_COPYRIGHTYEARS "2008-2017")
set (PROJECT_COPYRIGHTYEARS "2008-2019")
set (PROJECT_AUTHORS "Sony Pictures Imageworks, et al")
set (PROJECT_URL "")
@@ -55,9 +55,9 @@ endif ()
include (GNUInstallDirs)
set (CMAKE_MODULE_PATH
"${PROJECT_SOURCE_DIR}/src/cmake/modules"
"${PROJECT_SOURCE_DIR}/src/cmake")
list (APPEND CMAKE_MODULE_PATH
"${PROJECT_SOURCE_DIR}/src/cmake/modules"
"${PROJECT_SOURCE_DIR}/src/cmake")
include (platform)
include (compiler) # All the C++ and compiler related options live here
@@ -81,6 +81,8 @@ endif()
option (VERBOSE "Print lots of messages while compiling" OFF)
set (${PROJ_NAME}_NAMESPACE ${PROJECT_NAME} CACHE STRING "Customized outer namespace base name (version will be added)")
set (SOVERSION ${OSL_VERSION_MAJOR}.${OSL_VERSION_MINOR}
CACHE STRING "Set the SO version in the SO name of the output library")
option (OSL_BUILD_TESTS "Build the unit tests, testshade, testrender" ON)
if (WIN32)
option (USE_LLVM_BITCODE "Generate embedded LLVM bitcode" OFF)
@@ -89,12 +91,16 @@ else ()
endif ()
option (USE_PARTIO "Use Partio if found" ON)
set (PARTIO_HOME "" CACHE STRING "Search path for Partio components")
option (USE_EXTERNAL_PUGIXML "Use an externally built shared library version of the pugixml library" OFF)
set (PUGIXML_HOME "" CACHE STRING "Hint about where to find external PugiXML library")
option (USE_FAST_MATH "Use fast math approximations (if no, then use system math library)" ON)
option (OSL_BUILD_PLUGINS "Bool OSL plugins, for example OIIO plugin" ON)
option (OSL_BUILD_SHADERS "Build shaders" ON)
option (OSL_BUILD_MATERIALX "Build MaterialX shaders" ON)
option (USE_BOOST_WAVE "Use Boost Wave for C preprocessor (alternative is to use clang)" OFF)
option (USE_QT "Include Qt support" ON)
option (USE_OPTIX "Include OptiX support" OFF)
set (OPTIX_EXTRA_LIBS CACHE STRING "Extra lib targets needed for OptiX")
set (CUDA_TARGET_ARCH "sm_35" CACHE STRING "CUDA GPU architecture (e.g. sm_35)")
# set (USE_OIIO_STATIC ON CACHE BOOL "If OIIO is built static")
# if (USE_OIIO_STATIC)
@@ -113,8 +119,13 @@ else ()
endif ()
# Set the default namespace
# Set the default namespace. For symbol hiding reasons, it's important that
# the project name is a subset of the namespace name.
set (PROJ_NAMESPACE "${${PROJ_NAME}_NAMESPACE}")
string(REGEX MATCH ${PROJECT_NAME} NAMESPACE_HAS_PROJECT_NAME ${PROJ_NAMESPACE})
if (NOT NAMESPACE_HAS_PROJECT_NAME)
set (PROJ_NAMESPACE ${PROJECT_NAME}_${PROJ_NAMESPACE})
endif ()
set (PROJ_NAMESPACE_V "${PROJ_NAMESPACE}_v${PROJECT_VERSION_MAJOR}_${PROJECT_VERSION_MINOR}")
message(STATUS "Setting Namespace to: ${PROJ_NAMESPACE_V}")
@@ -156,17 +167,34 @@ add_subdirectory (src/testshade)
add_subdirectory (src/testrender)
endif ()
if (OSL_BUILD_TESTS AND USE_OPTIX)
add_subdirectory (src/testoptix)
endif()
if (OSL_BUILD_PLUGINS)
add_subdirectory (src/osl.imageio)
endif ()
add_subdirectory (src/shaders)
add_subdirectory (src/shaders/MaterialX)
if (USE_QT AND Qt5_FOUND)
add_subdirectory (src/osltoy)
endif ()
if (OSL_BUILD_SHADERS)
add_subdirectory (src/shaders)
if (OSL_BUILD_MATERIALX)
add_subdirectory (src/shaders/MaterialX)
endif ()
endif ()
if (INSTALL_DOCS)
add_subdirectory (src/doc)
endif ()
# Oddball: install the FindOSL.cmake file
# install (FILES src/cmake/modules/FindOSL.cmake
# DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/Modules
# COMPONENT cmake)
#########################################################################
@@ -212,13 +240,13 @@ macro ( TESTSUITE )
NOT _testname MATCHES "^oslinfo" AND
NOT _testname MATCHES "^getattribute-shader" AND
NOT EXISTS "${_testsrcdir}/OPTIMIZEONLY")
set (_env TESTSHADE_OPT=0 OPENIMAGEIOHOME=${OPENIMAGEIOHOME})
set (_env TESTSHADE_OPT=0 OPENIMAGEIO_ROOT_DIR=${OPENIMAGEIO_ROOT_DIR})
add_test ( NAME ${_testname}
COMMAND env ${_env} ${_runtest} )
endif ()
# Run the same test again with aggressive -O2 runtime
# optimization, triggered by setting TESTSHADE_OPT env variable
set (_env TESTSHADE_OPT=2 OPENIMAGEIOHOME=${OPENIMAGEIOHOME})
set (_env TESTSHADE_OPT=2 OPENIMAGEIO_ROOT_DIR=${OPENIMAGEIO_ROOT_DIR})
set (ALL_TEST_LIST "${ALL_TEST_LIST} ${_testname}")
add_test ( NAME ${_testname}.opt
COMMAND env ${_env} ${_runtest} )
@@ -231,24 +259,28 @@ endmacro ()
if (OSL_BUILD_TESTS)
# List all the individual testsuite tests here, except those that need
# special installed tests.
TESTSUITE ( and-or-not-synonyms aastep arithmetic array array-derivs array-range
TESTSUITE ( aastep allowconnect-err and-or-not-synonyms arithmetic
array array-derivs array-range array-aassign
blackbody blendmath breakcont
bug-array-heapoffsets
bug-locallifetime bug-outputinit bug-param-duplicate bug-peep
cellnoise closure closure-array color comparison
compile-buffer
component-range const-array-params const-array-fill
component-range
connect-components
const-array-params const-array-fill
debugnan debug-uninit
derivs derivs-muldiv-clobber
draw_string
error-dupes exit exponential
fprintf
function-earlyreturn function-simple function-outputelem
function-overloads function-redef
geomath getattribute-camera getattribute-shader
getsymbol-nonheap gettextureinfo
group-outputs groupstring
hash hashnoise hex hyperb
ieee_fp if incdec initops intbits isconnected isconstant
ieee_fp if incdec initlist initops intbits isconnected isconstant
layers layers-Ciassign layers-entry layers-lazy
layers-nonlazycopy layers-repeatedoutputs
linearstep
@@ -257,16 +289,20 @@ TESTSUITE ( and-or-not-synonyms aastep arithmetic array array-derivs array-range
metadata-braces miscmath missing-shader
noise noise-cell
noise-gabor noise-gabor2d-filter noise-gabor3d-filter
noise-perlin noise-uperlin noise-simplex noise-usimplex
pnoise pnoise-cell pnoise-gabor pnoise-perlin pnoise-uperlin
noise-perlin noise-simplex
pnoise pnoise-cell pnoise-gabor pnoise-perlin
operator-overloading
oslc-comma oslc-D
oslc-err-arrayindex oslc-err-closuremul
oslc-err-format oslc-err-intoverflow
oslc-err-arrayindex oslc-err-assignmenttypes
oslc-err-closuremul oslc-err-field
oslc-err-format oslc-err-funcoverload
oslc-err-intoverflow oslc-err-write-nonoutput
oslc-err-noreturn oslc-err-notfunc
oslc-err-initlist-args oslc-err-initlist-return
oslc-err-outputparamvararray oslc-err-paramdefault
oslc-err-struct-array-init oslc-err-struct-ctr
oslc-err-struct-dup
oslc-err-struct-dup oslc-err-struct-print
oslc-err-unknown-ctr
oslc-warn-commainit
oslc-variadic-macro
oslc-version
@@ -274,12 +310,13 @@ TESTSUITE ( and-or-not-synonyms aastep arithmetic array array-derivs array-range
oslinfo-metadata oslinfo-noparams
osl-imageio
paramval-floatpromotion
pragma-nowarn
printf-whole-array
raytype raytype-specialized reparam
render-background render-bumptest
render-cornell render-furnace-diffuse
render-microfacet render-oren-nayar render-veachmis render-ward
select shortcircuit spline splineinverse
select shortcircuit spline splineinverse splineinverse-ident
spline-boundarybug spline-derivbug
string
struct struct-array struct-array-mixture
@@ -302,10 +339,10 @@ TESTSUITE ( and-or-not-synonyms aastep arithmetic array array-derivs array-range
vararray-connect vararray-default
vararray-deserialize vararray-param
vecctr vector
wavelength_color xml )
wavelength_color Werror xml )
# Only run field3d-related tests if the local OIIO was built with f3d support.
EXECUTE_PROCESS ( COMMAND ${OPENIMAGEIO_BIN}/oiiotool --help
EXECUTE_PROCESS ( COMMAND ${OPENIMAGEIO_BIN} --help
OUTPUT_VARIABLE oiiotool_help )
if (oiiotool_help MATCHES "field3d")
TESTSUITE ( texture-field3d )
@@ -316,6 +353,11 @@ if (PARTIO_FOUND)
TESTSUITE ( pointcloud pointcloud-fold )
endif ()
# Only run the OptiX tests if OptiX and CUDA are found
if (OPTIX_FOUND AND CUDA_FOUND)
TESTSUITE ( testoptix testoptix-noise )
endif ()
# FIXME: still working on MaterialX testsuite
# add_subdirectory(testsuite/MaterialX)
+15 -9
View File
@@ -9,18 +9,19 @@ Dependencies
OSL requires the following dependencies or tools.
NEW or CHANGED dependencies since the last major release are **bold**.
* Build system: **[CMake](https://cmake.org/) 3.2.2 or newer**
* Build system: [CMake](https://cmake.org/) 3.2.2 or newer (tested through
3.14)
* A suitable **C++11** compiler to build OSL itself, which may be any of:
- GCC 4.8.5 or newer
- Clang 3.4 or newer
* A suitable C++11 compiler to build OSL itself, which may be any of:
- GCC 4.8.5 or newer (through gcc 8)
- Clang 3.4 or newer (through clang 8)
- Microsoft Visual Studio 2015 or newer
- Intel C++ compiler icc version 13 (?) or newer
OSL should compile also properly with C++14 or C++17, but they are not
required.
* **[OpenImageIO](http://openimageio.org) 1.7 or newer**
* **[OpenImageIO](http://openimageio.org) 1.8.5 or newer**
OSL uses OIIO both for its texture mapping functionality as well as
numerous utility classes. If you are integrating OSL into an existing
@@ -39,15 +40,15 @@ NEW or CHANGED dependencies since the last major release are **bold**.
DYLD_LIBRARY_PATH on OS X) and then OSL's build scripts will be able
to find it.
* **[LLVM](http://www.llvm.org) 3.5, 3.9, 4.0, or 5.0**
* **[LLVM](http://www.llvm.org) 4.0, 5.0, 6.0, 7.0, or 8.0**
Optionally, if Clang libraries are installed alongside LLVM, OSL will
in most circumstances use Clang's internals for C-style preprocessing of
OSL source. If not found, it will fall back on Boost Wave (but on many
platforms, that requires that Boost has been built in C++11 mode).
* [Boost](www.boost.org) 1.55 or newer.
* **[Ilmbase/OpenEXR](http://openexr.com/downloads.html) 2.0 or newer**
* [Boost](www.boost.org) 1.55 or newer (tested through 1.69).
* [Ilmbase/OpenEXR](http://openexr.com/downloads.html) 2.0 or newer
* [Flex](https://github.com/westes/flex) and
[GNU Bison](https://www.gnu.org/software/bison/)
* [PugiXML](http://pugixml.org/)
@@ -79,6 +80,11 @@ Here are the steps to check out, build, and test the OSL distribution:
options, and note that 'make nuke' will blow everything away for the
freshest possible compile.
NOTE: If the build breaks due to compiler warnings which have been
elevated to errors, you can try "make clean" followed by
"make STOP_ON_WARNING=0", that create a build that will only stop for
full errors, not warnings.
3. After compilation, you'll end up with a full OSL distribution in
dist/ARCH, where ARCH is the architecture you are building on, one of
"linux", "linux64", "macosx", "windows", or "windows64".
@@ -92,7 +98,7 @@ Here are the steps to check out, build, and test the OSL distribution:
of those files to appropriate directories. Public include files
(those needed when building applications that incorporate OSL)
can be found in "dist/ARCH/include", and documentation can be found
in "dist/ARCH/doc".
in "dist/ARCH/share/doc".
5. After building (and setting your library path), you can run the
test suite with:
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al.
Copyright (c) 2009-2019 Sony Pictures Imageworks Inc., et al.
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
+44 -17
View File
@@ -35,15 +35,10 @@ NINJA ?= ninja
CMAKE ?= cmake
# Site-specific build instructions
ifndef OSL_SITE
OSL_SITE := ${shell uname -n}
endif
OSL_SITE ?= ${shell uname -n}
ifneq (${shell echo ${OSL_SITE} | grep imageworks.com},)
include ${working_dir}/site/spi/Makefile-bits
endif
ifneq (${shell echo ${OSL_SITE} | grep pixar.com},)
include ${working_dir}/site/pixar/Makefile-bits
endif
# Set up variables holding the names of platform-dependent directories --
# set these after evaluating site-specific instructions
@@ -51,7 +46,7 @@ top_build_dir := build
build_dir := ${top_build_dir}/${platform}${variant}
top_dist_dir := dist
dist_dir := ${top_dist_dir}/${platform}${variant}
OSLHOME ?= ${working_dir}/${dist_dir}
OSL_ROOT_DIR ?= ${working_dir}/${dist_dir}
ifndef INSTALL_PREFIX
INSTALL_PREFIX := ${working_dir}/${dist_dir}
@@ -109,12 +104,20 @@ ifneq (${USE_FAST_MATH},)
MY_CMAKE_FLAGS += -DUSE_FAST_MATH:BOOL=${USE_FAST_MATH}
endif
# Old names -- DEPRECATED (1.9)
ifneq (${OPENEXR_HOME},)
MY_CMAKE_FLAGS += -DOPENEXR_HOME:STRING=${OPENEXR_HOME}
MY_CMAKE_FLAGS += -DOPENEXR_ROOT_DIR:STRING=${OPENEXR_HOME}
endif
ifneq (${ILMBASE_HOME},)
MY_CMAKE_FLAGS += -DILMBASE_ROOT_DIR:STRING=${ILMBASE_HOME}
endif
ifneq (${ILMBASE_HOME},)
MY_CMAKE_FLAGS += -DILMBASE_HOME:STRING=${ILMBASE_HOME}
ifneq (${OPENEXR_ROOT_DIR},)
MY_CMAKE_FLAGS += -DOPENEXR_ROOT_DIR:STRING=${OPENEXR_ROOT_DIR}
endif
ifneq (${ILMBASE_ROOT_DIR},)
MY_CMAKE_FLAGS += -DILMBASE_ROOT_DIR:STRING=${ILMBASE_ROOT_DIR}
endif
ifneq (${USE_PARTIO},)
@@ -129,6 +132,10 @@ ifneq (${BOOST_HOME},)
MY_CMAKE_FLAGS += -DBOOST_ROOT:STRING=${BOOST_HOME}
endif
ifneq (${USE_QT},)
MY_CMAKE_FLAGS += -DUSE_QT:BOOL=${USE_QT}
endif
ifneq (${STOP_ON_WARNING},)
MY_CMAKE_FLAGS += -DSTOP_ON_WARNING:BOOL=${STOP_ON_WARNING}
endif
@@ -137,6 +144,10 @@ ifneq (${BUILDSTATIC},)
MY_CMAKE_FLAGS += -DBUILDSTATIC:BOOL=${BUILDSTATIC}
endif
ifneq (${SOVERSION},)
MY_CMAKE_FLAGS += -DSOVERSION:STRING=${SOVERSION}
endif
ifneq (${LINKSTATIC},)
MY_CMAKE_FLAGS += -DLINKSTATIC:BOOL=${LINKSTATIC}
endif
@@ -145,8 +156,12 @@ ifneq (${OSL_BUILD_TESTS},)
MY_CMAKE_FLAGS += -DOSL_BUILD_TESTS:BOOL=${OSL_BUILD_TESTS}
endif
ifneq (${USE_EXTERNAL_PUGIXML},)
MY_CMAKE_FLAGS += -DUSE_EXTERNAL_PUGIXML:BOOL=${USE_EXTERNAL_PUGIXML} -DPUGIXML_HOME=${PUGIXML_HOME}
ifneq (${OSL_BUILD_SHADERS},)
MY_CMAKE_FLAGS += -DOSL_BUILD_SHADERS:BOOL=${OSL_BUILD_SHADERS}
endif
ifneq (${OSL_BUILD_MATERIALX},)
MY_CMAKE_FLAGS += -DOSL_BUILD_MATERIALX:BOOL=${OSL_BUILD_MATERIALX}
endif
ifdef DEBUG
@@ -172,6 +187,10 @@ ifneq (${USE_LIBCPLUSPLUS},)
MY_CMAKE_FLAGS += -DUSE_LIBCPLUSPLUS:BOOL=${USE_LIBCPLUSPLUS}
endif
ifneq (${GLIBCXX_USE_CXX11_ABI},)
MY_CMAKE_FLAGS += -DGLIBCXX_USE_CXX11_ABI=${GLIBCXX_USE_CXX11_ABI}
endif
ifneq (${EXTRA_CPP_ARGS},)
MY_CMAKE_FLAGS += -DEXTRA_CPP_ARGS:STRING="${EXTRA_CPP_ARGS}"
endif
@@ -216,6 +235,10 @@ ifneq (${CLANG_TIDY_FIX},)
# N.B. when fixing, you don't want parallel jobs!
endif
ifneq (${USE_OPTIX},)
MY_CMAKE_FLAGS += -DUSE_OPTIX:BOOL=${USE_OPTIX}
endif
#$(info MY_CMAKE_FLAGS = ${MY_CMAKE_FLAGS})
#$(info MY_MAKE_FLAGS = ${MY_MAKE_FLAGS})
@@ -304,7 +327,7 @@ test: cmake
@ ${CMAKE} -E cmake_echo_color --switch=$(COLOR) --cyan "Running tests ${TEST_FLAGS}..."
@ # if [ "${CODECOV}" == "1" ] ; then lcov -b ${build_dir} -d ${build_dir} -z ; rm -rf ${build_dir}/cov ; fi
@ ( cd ${build_dir} ; \
OSLHOME=${OSLHOME} \
OSL_ROOT_DIR=${OSL_ROOT_DIR} \
LD_LIBRARY_PATH=${INSTALL_PREFIX}/lib:${LD_LIBRARY_PATH} \
DYLD_LIBRARY_PATH=${INSTALL_PREFIX}/lib:${DYLD_LIBRARY_PATH} \
OIIO_LIBRARY_PATH=${INSTALL_PREFIX}/lib:${OIIO_LIBRARY_PATH} \
@@ -354,6 +377,7 @@ help:
@echo " MYCC=xx MYCXX=yy Use custom compilers"
@echo " USE_CPP=14 Compile in C++14 mode (default is C++11)"
@echo " USE_LIBCPLUSPLUS=1 Use clang libc++"
@echo " GLIBCXX_USE_CXX11_ABI=1 For gcc, use the new string ABI"
@echo " EXTRA_CPP_ARGS= Additional args to the C++ command"
@echo " USE_NINJA=1 Set up Ninja build (instead of make)"
@echo " USE_CCACHE=0 Disable ccache (even if available)"
@@ -367,10 +391,10 @@ help:
@echo " LINKSTATIC=1 Link with static external libs when possible"
@echo " Finding and Using Dependencies:"
@echo " BOOST_HOME=path Custom Boost installation"
@echo " OPENEXR_HOME=path Custom OpenEXR installation"
@echo " ILMBASE_HOME=path Custom Ilmbase installation"
@echo " PARTIO_HOME= Use Partio from the given location"
@echo " USE_EXTERNAL_PUGIXML=1 Use the system PugiXML, not the one in OIIO"
@echo " OPENEXR_ROOT_DIR=path Custom OpenEXR installation"
@echo " ILMBASE_ROOT_DIR=path Custom Ilmbase installation"
@echo " PARTIO_HOME=path Use Partio from the given location"
@echo " USE_QT=0 Skip anything that needs Qt"
@echo " LLVM-related options:"
@echo " LLVM_VERSION=4.0 Specify which LLVM version to use"
@echo " LLVM_DIRECTORY=xx Specify where LLVM lives"
@@ -383,9 +407,12 @@ help:
@echo " NAMESPACE=name Override namespace base name (default: OSL)"
@echo " USE_FAST_MATH=1 Use faster, but less accurate math (set to 0 for libm defaults)"
@echo " OSL_BUILD_TESTS=0 Don't build unit tests, testshade, testrender"
@echo " OSL_BUILD_SHADERS=0 Don't build any shaders"
@echo " OSL_BUILD_MATERIALX=0 Don't build MaterialX shaders"
@echo " USE_SIMD=arch Build with SIMD support (choices: 0, sse2, sse3,"
@echo " ssse3, sse4.1, sse4.2, f16c, avx, avx2"
@echo " comma-separated ok)"
@echo " USE_OPTIX=1 Build the OptiX test renderer"
@echo " make test, extra options:"
@echo " TEST=regex Run only tests matching the regex"
@echo ""
+54 -8
View File
@@ -9,6 +9,7 @@ Open Shading Language
Build status:
[![Build Status](https://travis-ci.org/imageworks/OpenShadingLanguage.svg?branch=master)](https://travis-ci.org/imageworks/OpenShadingLanguage)
[![Appveyor status](https://ci.appveyor.com/api/projects/status/github/imageworks/openshadinglanguage?svg=true&branch=master)](https://ci.appveyor.com/project/lgritz/openshadinglanguage)
**Table of contents**
@@ -242,6 +243,7 @@ adding OSL support):
* [DNA Research: 3Delight](http://www.3delight.com/)
* Ubisoft motion picture group's proprietary renderer
* [Autodesk/SolidAngle: Arnold](https://www.solidangle.com/arnold/)
* [Autodesk: 3DS Max 2019](https://help.autodesk.com/view/3DSMAX/2019/ENU/?guid=__developer_3ds_max_sdk_features_rendering_osl_html)
Films using OSL (grouped by year of release date):
* **(2012)**
@@ -275,8 +277,10 @@ Films using OSL (grouped by year of release date):
Suicide Squad,
Kingsglaive: Final Fantasy XV,
Storks,
Miss Peregrine's Home for Peculiar Children, Assassin's Creed
* **(2017) / upcoming**
Miss Peregrine's Home for Peculiar Children,
Fantastic Beasts and Where to Find Them,
Assassin's Creed
* **(2017)**
Lego Batman,
The Great Wall,
A Cure for Wellness,
@@ -296,9 +300,50 @@ Films using OSL (grouped by year of release date):
The Emoji Movie,
Detroit,
Kingsman: The Golden Circle,
Lega Ninjago Movie,
Lego Ninjago Movie,
Blade Runner 2049,
Geostorm,
Coco,
Justice League,
Thor: Ragnarok
* **(2018)**
Peter Rabbit,
Black Panther,
Annnihilation,
Red Sparrow,
Pacific Rim Uprising,
Avengers Infinity War,
Deadpool 2,
Incredibles 2,
Jurassic World: Fallen Kingdom,
Hotel Transylvania 3: Summer Vacation,
Ant Man and the Wasp,
Skyscraper,
Mission Impossible: Fallout,
The Meg,
Kin,
Smallfoot,
Alpha,
Venom,
First Man,
Bad Times at the El Royale,
Fantastic Beasts: The Crimes of Grindelwald,
Bohemian Rhapsody,
Holmes and Watson,
Spider-Man: Into the Spider-Verse
* **(2019 / upcoming)**
The Kid Who Would Be King,
Alita: Battle Angel,
Lego Movie 2,
Lucky 13,
Captain Marvel,
Avengers: Endgame,
Pokémon Detective Pikachu,
Godzilla: King of Monsters,
Rim of the World,
Men in Black International,
Toy Story 4,
Spider-Man: Far From Home,
...
@@ -339,11 +384,12 @@ Van Lommel.
Additionally, many others have contributed features, bug fixes, and other
changes: Steve Agland, Shane Ambler, Martijn Berger, Farchad Bidgolirad,
Nicholas Bishop, Stefan Büttner, Matthaus G. Chajdas, Thomas Dinges, Henri
Fousse, Syoyo Fujita, Derek Haase, Sven-Hendrik Haase, John Haddon, Daniel
Heckenberg, Ronan Keryell, Elvic Liang, Max Liani, Bastien Montagne, Erich
Ocean, Mikko Ohtamaa, Alex Schworer, Sergey Sharybin, Stephan Steinbach,
Esteban Tovagliari, Alexander von Knorring, Roman Zulak. (Listed
Nicholas Bishop, Stefan Büttner, Matthaus G. Chajdas, Thomas Dinges, Mark
Final, Henri Fousse, Syoyo Fujita, Tim Grant, Derek Haase, Sven-Hendrik
Haase, John Haddon, Daniel Heckenberg, Matt Johnson, Ronan Keryell, Elvic
Liang, Max Liani, Bastien Montagne, Alexis Oblet, Erich Ocean, Mikko
Ohtamaa, Alex Schworer, Jonathan Scruggs, Sergey Sharybin, Stephan
Steinbach, Esteban Tovagliari, Alexander von Knorring, Roman Zulak. (Listed
alphabetically; if we've left anybody out, please let us know.)
We cannot possibly express sufficient gratitude to the managers at Sony
+196
View File
@@ -0,0 +1,196 @@
clone_depth: 10
version: '{branch}-{build}'
# Disable Appveyor's test discovery which is not used
test: off
branches:
only:
- master
- release
- appveyor
- /RB-/
- /lg-/
skip_tags: true
build:
parallel: true
verbosity: detailed
platform:
- x64
# - x86
configuration:
#- Debug
- Release
environment:
matrix:
- TOOLSET: msvc14
os:
- Visual Studio 2015
cache:
- C:\projects\OSLdeps -> appveyor.yml
# The -> means that the cache dir is discarded if appveyor.yml has changed
before_build:
- ps: |
$OSL_INSTALL_BEGIN=Get-Date
Write-Output "Configuration: $env:CONFIGURATION"
Write-Output "Platform: $env:PLATFORM"
ls C:\Libraries\llvm-5.0.0
Get-ChildItem Env:
[Array]$OSL_BUILD_FLAGS = "--", "/nologo", "/verbosity:minimal";
$DWN_DIR = "C:\projects\OSLdownloads"
$DEP_DIR = "C:\projects\OSLdeps"
$BOOST_ROOT = "C:\Libraries\boost_1_63_0"
$PYTHON_DIR = "C:\Python27"
$LLVM_DIR = "C:\Libraries\llvm-5.0.0"
#$LLVM_DIR = "$DEP_DIR"
$env:Path += ";$DEP_DIR\lib;$DEP_DIR\bin"
$OSL_INT_DIR = "build\windows$env:PLATFORM"
# RDP into the build-bot to try some stuff out
# iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
# $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
# Choose the VisualStudio generator
$GENERATOR = switch ($env:TOOLSET)
{
"msvc14" {"Visual Studio 14 2015"}
"msvc12" {"Visual Studio 12 2013"}
"msvc11" {"Visual Studio 11 2012"}
"msvc10" {"Visual Studio 10 2010"}
}
# Final setup based on 64 or 32 bit
if ($env:PLATFORM -eq "x64") {
$GENERATOR = "$GENERATOR Win64"
$PYTHON_DIR = "$PYTHON_DIR-x64"
$BOOST_LIBRARYDIR = "$BOOST_ROOT\lib64-msvc-14.0"
} else {
$BOOST_LIBRARYDIR = "$BOOST_ROOT\lib32-msvc-14.0"
}
# Always create the download directory
md $DWN_DIR -Force | Out-Null;
# If the dependency directory exists/cached, use it
if(!(Test-Path -Path $DEP_DIR )){
md $DEP_DIR -Force | Out-Null; cd $DEP_DIR
md $DEP_DIR\include -Force | Out-Null; cd $DEP_DIR
md $DEP_DIR\lib -Force | Out-Null; cd $DEP_DIR
cd $DWN_DIR
nuget install libtiff-$env:TOOLSET-$env:PLATFORM-master -Version 4.0.6.85 -Source https://ci.appveyor.com/nuget/libtiff-i3h8tqqy7o7b
mv .\libtiff*\*.h $DEP_DIR\include\
mv .\libtiff*\*.lib $DEP_DIR\lib\
mv .\libtiff*\*.dll $DEP_DIR\lib\
nuget install libpng-$env:TOOLSET-$env:PLATFORM-master -Version 1.6.18.44 -Source https://ci.appveyor.com/nuget/libpng-7hwq4pmmrc48
mv .\libpng*\*.h $DEP_DIR\include\
mv .\libpng*\*.lib $DEP_DIR\lib\
mv .\libpng*\*.dll $DEP_DIR\lib\
nuget install libjpeg-$env:TOOLSET-$env:PLATFORM-master -Version 1.4.80.21 -Source https://ci.appveyor.com/nuget/libjpegturbo-o6k4js4y7pjw
mv .\libjpeg*\*.h $DEP_DIR\include\
mv .\libjpeg*\*.lib $DEP_DIR\lib\
mv .\libjpeg*\*.dll $DEP_DIR\lib\
nuget install freetype
mv .\freetype.2.8.0.1\build\native\include\* $DEP_DIR\include\
mv .\freetype.2.8.0.1\build\native\lib\$env:PLATFORM\v140\dynamic\$env:CONFIGURATION\*.lib $DEP_DIR\lib\
mv .\freetype.redist.2.8.0.1\build\native\bin\$env:PLATFORM\v140\dynamic\$env:CONFIGURATION\*.dll $DEP_DIR\lib\
# ZLib
cd $DWN_DIR
Start-FileDownload https://github.com/madler/zlib/archive/v1.2.8.tar.gz
tar -xzf v1.2.8.tar.gz; cd zlib-1.2.8; md "$OSL_INT_DIR" -Force | Out-Null; cd "$OSL_INT_DIR"
cmake ..\.. -G "$GENERATOR" -DCMAKE_CONFIGURATION_TYPES="$env:CONFIGURATION" -DCMAKE_PREFIX_PATH="$DEP_DIR" -DCMAKE_INSTALL_PREFIX="$DEP_DIR"
cmake --build . --config $env:CONFIGURATION --target INSTALL $OSL_BUILD_FLAGS
# IlmBase
cd $DWN_DIR
Start-FileDownload http://download.savannah.nongnu.org/releases/openexr/ilmbase-2.2.1.tar.gz
tar -xzf ilmbase-2.2.1.tar.gz ; cd ilmbase* ; md "$OSL_INT_DIR" -Force | Out-Null; cd "$OSL_INT_DIR"
cmake ..\.. -G "$GENERATOR" -DCMAKE_CONFIGURATION_TYPES="$env:CONFIGURATION" -DCMAKE_PREFIX_PATH="$DEP_DIR" -DCMAKE_INSTALL_PREFIX="$DEP_DIR" -DCMAKE_CXX_FLAGS=" /W1 /EHsc /DWIN32=1 "
cmake --build . --config $env:CONFIGURATION --target INSTALL $OSL_BUILD_FLAGS
# LLVM
# This shouldn't be necessary, we use the pre-installed LLVM
# cd $DWN_DIR
# git clone --depth 10 --branch release_40 https://github.com/llvm-mirror/llvm.git
# cd llvm; md "$OSL_INT_DIR" -Force | Out-Null; cd "$OSL_INT_DIR"
# cmake ..\.. -G "$GENERATOR" -DCMAKE_CONFIGURATION_TYPES="$env:CONFIGURATION" -DCMAKE_PREFIX_PATH="$DEP_DIR" -DCMAKE_INSTALL_PREFIX="$DEP_DIR" -DLLVM_TARGETS_TO_BUILD="X86"
# cmake --build . --config $env:CONFIGURATION --target INSTALL $OSL_BUILD_FLAGS
# OpenEXR
cd $DWN_DIR
Start-FileDownload http://download.savannah.nongnu.org/releases/openexr/openexr-2.2.1.tar.gz
tar -xzf openexr-2.2.1.tar.gz ; cd openexr* ; md "$OSL_INT_DIR" -Force | Out-Null; cd "$OSL_INT_DIR"
cmake ..\.. -G "$GENERATOR" -DCMAKE_CONFIGURATION_TYPES="$env:CONFIGURATION" -DCMAKE_PREFIX_PATH="$DEP_DIR" -DCMAKE_INSTALL_PREFIX="$DEP_DIR" -DILMBASE_PACKAGE_PREFIX="$DEP_DIR" -DCMAKE_CXX_FLAGS=" /W1 /EHsc /DWIN32=1 "
cmake --build . --config $env:CONFIGURATION --target INSTALL $OSL_BUILD_FLAGS
}
# Always do this
cinst winflexbison
build_script:
- ps: |
# OpenImageIO
$env:OPENIMAGEIO_ROOT_DIR = "C:\projects\oiio"
$env:FREETYPE_DIR = "$DEP_DIR"
$FREETYPE_LIBRARY = "$DEP_DIR\lib\freetype28.lib"
cd $DWN_DIR
git clone --depth 10 https://github.com/OpenImageIO/oiio.git oiiosrc
cd .\oiiosrc; md "$OSL_INT_DIR" -Force | Out-Null; cd "$OSL_INT_DIR"
cmake ..\.. -G "$GENERATOR" -DCMAKE_CONFIGURATION_TYPES="$env:CONFIGURATION" -DCMAKE_INSTALL_PREFIX="$env:OPENIMAGEIO_ROOT_DIR" -DCMAKE_PREFIX_PATH="$DEP_DIR;$BOOST_ROOT" -DBOOST_LIBRARYDIR="$BOOST_LIBRARYDIR" -DFREETYPE_LIBRARY="$FREETYPE_LIBRARY" -DUSE_PYTHON=OFF -DOIIO_BUILD_TESTS=OFF -DUSE_NUKE=OFF
cmake --build . --config $env:CONFIGURATION --target INSTALL $OSL_BUILD_FLAGS
# Build OSL
cd $env:APPVEYOR_BUILD_FOLDER
md "$OSL_INT_DIR" -Force | Out-Null; cd "$OSL_INT_DIR"
cmake ..\.. -G "$GENERATOR" -DCMAKE_CONFIGURATION_TYPES="$env:CONFIGURATION" -DCMAKE_PREFIX_PATH="$env:OPENIMAGEIO_ROOT_DIR;$DEP_DIR;$BOOST_ROOT;$LLVM_DIR" -DCMAKE_INSTALL_PREFIX="$DEP_DIR" -DLLVM_DIRECTORY="$LLVM_DIR" -DLLVM_STATIC=ON -DOPENIMAGEIO_ROOT_DIR="$env:OPENIMAGEIO_ROOT_DIR" -DBOOST_LIBRARYDIR="$BOOST_LIBRARYDIR" -DFLEX_EXECUTABLE="C:\ProgramData\chocolatey\lib\winflexbison\tools\win_flex.exe" -DBISON_EXECUTABLE="C:\ProgramData\chocolatey\lib\winflexbison\tools\win_bison.exe" -DUSE_QT=OFF -DBUILDSTATIC=OFF -DLINKSTATIC=OFF
# OSL's CMake should probably be handling Windows config better...
$OSL_BUILD_DIR = "$env:APPVEYOR_BUILD_FOLDER\$OSL_INT_DIR"
$env:OSL_ROOT_DIR = "$env:APPVEYOR_BUILD_FOLDER\src"
$env:OIIO_LIBRARY_PATH = "$OSL_BUILD_DIR\src\osl.imageio\$env:CONFIGURATION"
$env:Path += ";$OSL_BUILD_DIR\src\oslc\$env:CONFIGURATION"
$env:Path += ";$OSL_BUILD_DIR\src\oslinfo\$env:CONFIGURATION"
$env:Path += ";$OSL_BUILD_DIR\src\liboslcomp\$env:CONFIGURATION"
$env:Path += ";$OSL_BUILD_DIR\src\liboslexec\$env:CONFIGURATION"
$env:Path += ";$OSL_BUILD_DIR\src\liboslnoise\$env:CONFIGURATION"
$env:Path += ";$OSL_BUILD_DIR\src\liboslquery\$env:CONFIGURATION"
$env:Path += ";$env:OPENIMAGEIO_ROOT_DIR\lib;$env:OPENIMAGEIO_ROOT_DIR\bin"
$env:Path += ";$BOOST_LIBRARYDIR"
cmake --build . --config $env:CONFIGURATION $OSL_BUILD_FLAGS
$OSL_BUILD_END=Get-Date
if(($OSL_BUILD_END-$OSL_INSTALL_BEGIN).TotalMinutes -gt 50) {
# Change to appveyor.yml means the cache needs to be rebuilt leaving
# us with not enough time to run the tests.
echo "OSL tests skipped in favor of uploading dependency cache"
# Echo to build log and Appveyors message page
Add-AppveyorMessage -Message "OSL tests skipped in favor of uploading dependency cache" -Category Warning
} else {
# Test OSL
ctest -C $env:CONFIGURATION --output-on-failure
}
#init:
#- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
#on_failure:
#- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
-27
View File
@@ -1,27 +0,0 @@
# Pixar-specific settings
ifneq (${VERBOSE},)
$(info Including pixar/Makefile-bits)
endif
MY_CMAKE_FLAGS += -DUSE_fPIC:BOOL=1
MY_CMAKE_FLAGS += -DENABLERTTI:BOOL=1
MY_CMAKE_FLAGS += -DSTOP_ON_WARNING:BOOL=0
MY_CMAKE_FLAGS += -DHIDE_SYMBOLS:BOOL=1
MY_CMAKE_FLAGS += -DBUILDSTATIC:BOOL=1
MY_CMAKE_FLAGS += -DLINKSTATIC:BOOL=1
MY_CMAKE_FLAGS += -DUSE_FAST_MATH:BOOL=1
MY_CMAKE_FLAGS += -DOPENEXR_CUSTOM_LIB_DIR:STRING=${ILMBASE_HOME}/lib/linux-ix86-64/gcc4.1
MY_CMAKE_FLAGS += -DOPENEXR_CUSTOM_LIB_SUFFIX:STRING="-fPIC"
# Don't build testshade or testrender (mostly because they require the
# image-handling parts of OIIO, which Pixar doesn't build)
MY_CMAKE_FLAGS += -DOSL_BUILD_TESTS:BOOL=0
# Don't let OSL create a default OIIO::TextureSystem. If the renderer
# doesn't pass in whatever proxy it wants, it will assert.
MY_CMAKE_FLAGS += -DOSL_NO_DEFAULT_TEXTURESYSTEM:BOOL=1
ifneq (${VERBOSE},)
$(info MY_CMAKE_FLAGS: $(MY_CMAKE_FLAGS))
endif
+44 -17
View File
@@ -15,10 +15,12 @@ ifeq ($(SP_OS), rhel7)
MY_CMAKE_FLAGS += -DCMAKE_MAKE_PROGRAM=${NINJA}
# Override lib64 and use SPI convention of lib
MY_CMAKE_FLAGS += -DCMAKE_INSTALL_LIBDIR="${INSTALL_PREFIX}/lib"
MY_CMAKE_FLAGS += -DCUDA_TOOLKIT_ROOT_DIR=/net/soft_scratch/apps/arnold/tools/nvidia/cuda8.0 -DOPTIX_EXTRA_LIBS=lzma
MY_CMAKE_FLAGS += -DOPTIXHOME=/net/soft_scratch/apps/arnold/tools/nvidia/NVIDIA-OptiX-SDK-5.1.0-linux64
## If not overridden, here is our preferred LLVM installation
## (may be changed as new versions are rolled out to the facility)
LLVM_DIRECTORY ?= /shots/spi/home/lib/arnold/rhel7/llvm_5.0.0
LLVM_DIRECTORY ?= /shots/spi/home/lib/arnold/rhel7/llvm_7.0.0
# A variety of tags can be used to try specific versions of gcc or
# clang from the site-specific places we have installed them.
@@ -28,14 +30,26 @@ ifeq ($(SP_OS), rhel7)
-DCMAKE_CXX_COMPILER=/shots/spi/home/lib/arnold/rhel7/llvm_4.0_final/bin/clang++
else ifeq (${COMPILER}, clang5)
MY_CMAKE_FLAGS += \
-DCMAKE_C_COMPILER=/shots/spi/home/lib/arnold/rhel7/llvm_5.0.0/bin/clang \
-DCMAKE_CXX_COMPILER=/shots/spi/home/lib/arnold/rhel7/llvm_5.0.0/bin/clang++
-DCMAKE_C_COMPILER=/shots/spi/home/lib/arnold/rhel7/llvm_5.0.1/bin/clang \
-DCMAKE_CXX_COMPILER=/shots/spi/home/lib/arnold/rhel7/llvm_5.0.1/bin/clang++
else ifeq (${COMPILER}, clang6)
MY_CMAKE_FLAGS += \
-DCMAKE_C_COMPILER=/shots/spi/home/lib/arnold/rhel7/llvm_6.0.1/bin/clang \
-DCMAKE_CXX_COMPILER=/shots/spi/home/lib/arnold/rhel7/llvm_6.0.1/bin/clang++
else ifeq (${COMPILER}, clang7)
MY_CMAKE_FLAGS += \
-DCMAKE_C_COMPILER=/shots/spi/home/lib/arnold/rhel7/llvm_7.0.0/bin/clang \
-DCMAKE_CXX_COMPILER=/shots/spi/home/lib/arnold/rhel7/llvm_7.0.0/bin/clang++
else ifeq (${COMPILER},clang)
MY_CMAKE_FLAGS += -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
else ifeq (${COMPILER}, gcc490)
MY_CMAKE_FLAGS += \
-DCMAKE_C_COMPILER=/net/soft_scratch/apps/arnold/tools/gcc-4.9-20130512-test/bin/gcc \
-DCMAKE_CXX_COMPILER=/net/soft_scratch/apps/arnold/tools/gcc-4.9-20130512-test/bin/g++
else ifeq (${COMPILER}, gcc6)
MY_CMAKE_FLAGS += \
-DCMAKE_C_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/gcc \
-DCMAKE_CXX_COMPILER=/opt/rh/devtoolset-6/root/usr/bin/g++
else ifeq (${COMPILER},gcc)
MY_CMAKE_FLAGS += -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
else ifeq (${COMPILER},)
@@ -43,11 +57,15 @@ ifeq ($(SP_OS), rhel7)
MY_CMAKE_FLAGS += \
-DCMAKE_C_COMPILER=${LLVM_DIRECTORY}/bin/clang \
-DCMAKE_CXX_COMPILER=${LLVM_DIRECTORY}/bin/clang++
MY_CMAKE_FLAGS += -DCMAKE_C_FLAGS="--gcc-toolchain=/usr" \
-DCMAKE_CXX_FLAGS="--gcc-toolchain=/usr" \
-DTOOLCHAIN_FLAGS="--gcc-toolchain=/usr"
endif
MY_CMAKE_FLAGS += \
-DOPENEXR_CUSTOM_INCLUDE_DIR=/usr/include/OpenEXR2 \
-DOPENEXR_CUSTOM_LIB_DIR=/usr/lib64/OpenEXR2 \
-DOPENEXR_INCLUDE_DIR=/usr/include/OpenEXR2 \
-DOPENEXR_LIBRARY_DIR=/usr/lib64/OpenEXR2 \
-DPARTIO_HOME="/shots/spi/home/lib/SpComp2/partio/rhel7-gcc48m64/v1" \
-DLLVM_STATIC=1 \
-DLLVM_VERSION=${LLVM_VERSION} \
@@ -56,17 +74,26 @@ ifeq ($(SP_OS), rhel7)
ifneq (${SPCOMP2_USE_BOOSTVERS}, 1)
BOOSTVERS=1.55
endif
BOOSTVERSSP=${BOOSTVERS}sp
BOOSTSPSUFFIX ?=
BOOSTVERSSP=${BOOSTVERS}${BOOSTSPSUFFIX}
BOOSTVERS_SUFFIX = -${shell echo ${BOOSTVERS} | sed "s/\\./_/"}
BOOSTVERS_PREFIX = ${shell echo ${BOOSTVERS} | sed "s/\\./_/"}_0
CONSTRUCTED_BOOSTVERS = ${shell echo ${BOOSTVERS} | sed "s/\\./0/"}00
MY_CMAKE_FLAGS += \
-DBOOST_CUSTOM=1 \
-DBoost_VERSION=${CONSTRUCTED_BOOSTVERS} \
-DBoost_INCLUDE_DIRS=/usr/include/boost_${BOOSTVERSSP} \
-DBoost_LIBRARY_DIRS=/usr/lib64/boost_${BOOSTVERS} \
-DBoost_LIBRARIES:STRING="/usr/lib64/boost_${BOOSTVERSSP}/libspboost_${BOOSTVERS_PREFIX}_filesystem-gcc48-mt${BOOSTVERS_SUFFIX}.so;/usr/lib64/boost_${BOOSTVERSSP}/libspboost_${BOOSTVERS_PREFIX}_regex-gcc48-mt${BOOSTVERS_SUFFIX}.so;/usr/lib64/boost_${BOOSTVERSSP}/libspboost_${BOOSTVERS_PREFIX}_system-gcc48-mt${BOOSTVERS_SUFFIX}.so;/usr/lib64/boost_${BOOSTVERSSP}/libspboost_${BOOSTVERS_PREFIX}_thread-gcc48-mt${BOOSTVERS_SUFFIX}.so;/usr/lib64/boost_${BOOSTVERSSP}/libspboost_${BOOSTVERS_PREFIX}_wave-gcc48-mt${BOOSTVERS_SUFFIX}.so"
MY_CMAKE_FLAGS += \
-DBOOST_CUSTOM=1 \
-DBoost_VERSION=${CONSTRUCTED_BOOSTVERS} \
-DBoost_INCLUDE_DIRS=/usr/include/boost_${BOOSTVERSSP} \
-DBoost_LIBRARY_DIRS=/usr/lib64/boost_${BOOSTVERS}
ifeq (${BOOSTSPSUFFIX}, sp)
MY_CMAKE_FLAGS += \
-DBoost_LIBRARIES:STRING="/usr/lib64/boost_${BOOSTVERSSP}/lib${BOOSTSPSUFFIX}boost_${BOOSTVERS_PREFIX}_regex-gcc48-mt${BOOSTVERS_SUFFIX}.so;/usr/lib64/boost_${BOOSTVERSSP}/lib${BOOSTSPSUFFIX}boost_${BOOSTVERS_PREFIX}_system-gcc48-mt${BOOSTVERS_SUFFIX}.so;/usr/lib64/boost_${BOOSTVERSSP}/lib${BOOSTSPSUFFIX}boost_${BOOSTVERS_PREFIX}_thread-gcc48-mt${BOOSTVERS_SUFFIX}.so"
else
MY_CMAKE_FLAGS += \
-DBoost_LIBRARIES:STRING="/usr/lib64/boost_${BOOSTVERSSP}/lib${BOOSTSPSUFFIX}boost_regex-gcc48-mt${BOOSTVERS_SUFFIX}.so;/usr/lib64/boost_${BOOSTVERSSP}/lib${BOOSTSPSUFFIX}boost_system-gcc48-mt${BOOSTVERS_SUFFIX}.so;/usr/lib64/boost_${BOOSTVERSSP}/lib${BOOSTSPSUFFIX}boost_thread-gcc48-mt${BOOSTVERS_SUFFIX}.so"
endif
# end rhel7
## Generic OSX machines (including LG's laptop)
@@ -89,10 +116,10 @@ else ifeq (${platform}, macosx)
MY_CMAKE_FLAGS += \
-DCMAKE_C_COMPILER=gcc-6 -DCMAKE_CXX_COMPILER=g++-6
USE_LIBCPLUSPLUS := 0
else ifeq (${COMPILER},clang35)
MY_CMAKE_FLAGS += -DCMAKE_C_COMPILER=clang-3.5 -DCMAKE_CXX_COMPILER=clang++-3.5
else ifeq (${COMPILER},clang40)
MY_CMAKE_FLAGS += -DCMAKE_C_COMPILER=/usr/local/opt/llvm@4/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@4/bin/clang++
else ifeq (${COMPILER},clang7)
MY_CMAKE_FLAGS += -DCMAKE_C_COMPILER=/usr/local/Cellar/llvm/7.0.0rc1/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/Cellar/llvm/7.0.0rc1/bin/clang++
else ifeq (${COMPILER},clang)
MY_CMAKE_FLAGS += -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
else ifeq (${COMPILER},gcc)
@@ -112,10 +139,10 @@ endif # endif $(SP_OS)
# set up OpenImageIO distribution environment
ifeq (${OPENIMAGEIOHOME},)
MY_CMAKE_FLAGS += -DOPENIMAGEIOHOME:STRING=${working_dir}/../OpenImageIO_local/dist/${platform}${variant}/
ifeq (${OPENIMAGEIO_ROOT_DIR},)
MY_CMAKE_FLAGS += -DOPENIMAGEIO_ROOT_DIR:STRING=${working_dir}/../OpenImageIO_local/dist/${platform}${variant}/
else
MY_CMAKE_FLAGS += -DOPENIMAGEIOHOME:STRING=${IMAGEIOHOME}
MY_CMAKE_FLAGS += -DOPENIMAGEIO_ROOT_DIR:STRING=${OPENIMAGEIO_ROOT_DIR}
endif
+45 -23
View File
@@ -1,48 +1,62 @@
#!/bin/bash
# The Linux VM used by Travis has OpenEXR 1.x. We really want 2.x.
# This script downloads and builds OpenEXR in the ext/ subdirectory.
EXRREPO=${EXRREPO:=https://github.com/openexr/openexr.git}
EXRINSTALLDIR=${EXRINSTALLDIR:=${PWD}/openexr-install}
EXRBRANCH=${EXRBRANCH:=v2.2.0}
EXRINSTALLDIR=${EXRINSTALLDIR:=${PWD}/ext/openexr-install}
EXRBRANCH=${EXRBRANCH:=v2.3.0}
EXRCXXFLAGS=${EXRCXXFLAGS:=""}
BASEDIR=`pwd`
pwd
echo "EXR install dir will be: ${EXRINSTALLDIR}"
if [ ! -e ${EXRINSTALLDIR} ] ; then
mkdir ${EXRINSTALLDIR}
if [[ ! -e ${EXRINSTALLDIR} ]] ; then
mkdir -p ${EXRINSTALLDIR}
fi
# Clone OpenEXR project (including IlmBase) from GitHub and build
if [ ! -e ./openexr ] ; then
echo "git clone ${EXRREPO} ./openexr"
git clone ${EXRREPO} ./openexr
if [[ ! -e ./ext/openexr ]] ; then
echo "git clone ${EXRREPO} ./ext/openexr"
git clone ${EXRREPO} ./ext/openexr
fi
flags=
if [ ${LINKSTATIC:=0} == 1 ] ; then
if [[ ${LINKSTATIC:=0} == 1 ]] ; then
flags=${flags} --enable-static --enable-shared=no --with-pic
fi
pushd ./openexr
pushd ./ext/openexr
echo "git checkout ${EXRBRANCH} --force"
git checkout ${EXRBRANCH} --force
cd IlmBase
mkdir build
cd build
cmake --config Release -DCMAKE_INSTALL_PREFIX=${EXRINSTALLDIR} -DCMAKE_CXX_FLAGS=${EXRCXXFLAGS} .. && make clean && make -j 4 && make install
cd ..
cd ../OpenEXR
cp ${BASEDIR}/src/build-scripts/OpenEXR-CMakeLists.txt CMakeLists.txt
cp ${BASEDIR}/src/build-scripts/OpenEXR-IlmImf-CMakeLists.txt IlmImf/CMakeLists.txt
mkdir build
mkdir build/IlmImf
cd build
unzip -d IlmImf ${BASEDIR}/src/build-scripts/b44ExpLogTable.h.zip
unzip -d IlmImf ${BASEDIR}/src/build-scripts/dwaLookups.h.zip
cmake --config Release -DCMAKE_INSTALL_PREFIX=${EXRINSTALLDIR} -DILMBASE_PACKAGE_PREFIX=${EXRINSTALLDIR} -DBUILD_UTILS=0 -DBUILD_TESTS=0 -DCMAKE_CXX_FLAGS=${EXRCXXFLAGS} .. && make clean && make -j 4 && make install
if [[ ${EXRBRANCH} == "v2.3.0" ]] ; then
# Simplified setup for 2.3+
mkdir build
cd build
mkdir OpenEXR
mkdir OpenEXR/IlmImf
unzip -d OpenEXR/IlmImf ${BASEDIR}/src/build-scripts/b44ExpLogTable.h.zip
unzip -d OpenEXR/IlmImf ${BASEDIR}/src/build-scripts/dwaLookups.h.zip
cmake --config Release -DCMAKE_INSTALL_PREFIX=${EXRINSTALLDIR} -DILMBASE_PACKAGE_PREFIX=${EXRINSTALLDIR} -DOPENEXR_BUILD_UTILS=0 -DOPENEXR_BUILD_TESTS=0 -DOPENEXR_BUILD_PYTHON_LIBS=0 -DCMAKE_CXX_FLAGS=${EXRCXXFLAGS} .. && make clean && make -j 4 && make install
else
cd IlmBase
mkdir build
cd build
cmake --config Release -DCMAKE_INSTALL_PREFIX=${EXRINSTALLDIR} -DCMAKE_CXX_FLAGS=${EXRCXXFLAGS} .. && make clean && make -j 4 && make install
cd ..
cd ../OpenEXR
cp ${BASEDIR}/src/build-scripts/OpenEXR-CMakeLists.txt CMakeLists.txt
cp ${BASEDIR}/src/build-scripts/OpenEXR-IlmImf-CMakeLists.txt IlmImf/CMakeLists.txt
mkdir build
mkdir build/IlmImf
cd build
unzip -d IlmImf ${BASEDIR}/src/build-scripts/b44ExpLogTable.h.zip
unzip -d IlmImf ${BASEDIR}/src/build-scripts/dwaLookups.h.zip
cmake --config Release -DCMAKE_INSTALL_PREFIX=${EXRINSTALLDIR} -DILMBASE_PACKAGE_PREFIX=${EXRINSTALLDIR} -DBUILD_UTILS=0 -DBUILD_TESTS=0 -DCMAKE_CXX_FLAGS=${EXRCXXFLAGS} .. && make clean && make -j 4 && make install
fi
popd
ls -R ${EXRINSTALLDIR}
@@ -50,3 +64,11 @@ ls -R ${EXRINSTALLDIR}
#echo "listing .."
#ls ..
# Set up paths. These will only affect the caller if this script is
# run with 'source' rather than in a separate shell.
export ILMBASE_ROOT_DIR=$EXRINSTALLDIR
export OPENEXR_ROOT_DIR=$EXRINSTALLDIR
export ILMBASE_LIBRARY_DIR=$EXRINSTALLDIR/lib
export OPENEXR_LIBRARY_DIR=$EXRINSTALLDIR/lib
export LD_LIBRARY_PATH=$OPENEXR_ROOT_DIR/lib:$LD_LIBRARY_PATH
+443
View File
@@ -0,0 +1,443 @@
#!/usr/bin/env python3
from __future__ import print_function
# Copyright (c) 2018 Sony Pictures Imageworks Inc., et al.
# BSD 3-clause license.
# Distributed as part of Open Shading Language.
# https://github.com/imageworks/OpenShadingLanguage
# ----------------------------------------------------------------------
# To generate docdeep for docdeep, run this:
# python3 docdeep.py -d docdeep docdeep.py > docdeep.md.html
# ----------------------------------------------------------------------
### <doc docdeep>
###
### **docdeep**
###
### Introduction
### ============
###
### `docdeep` is a utility that extracts documentation from source code and
### turns them into beautiful Markdeep documents.
###
### [Markdeep](https://casual-effects.com/markdeep) is a package by Morgan
### McGuire, an extension of Markdown with a whole bunch of nice features
### that make it extra nice for code, math, and diagrams. Read the Markdeep
### web page and look at the examples for details.
###
### `docdeep` is a little like `Doxygen`. A poor person's Doxygen. A very
### poor person. But without Doxygen's awkward syntax -- you just write
### the comments in Markdeep. And the output is very aesthetically pleasing.
### But it doesn't have any bells and whistles, like cross-referencing.
###
###
###
### Markup controls
### ===============
###
### ## Documentation lines.
###
### A line whose first three non-whitespace characters are either `///` or
### `###` is called a *doc-line*. Any other line is a *non-doc-line*.
###
### The `///` or `###` is the *doc-symbol*. Generally speaking, the `///`
### doc-symbol is used when doc-marking C or C++, and `###` when doc-marking
### Python, shell scripts, or other programs in languages where `#` is the
### comment character. For simplicity, in the rest of this document, we will
### always use `///` in our examples.
###
### ## Doc regions
###
### Doc-lines by themeslves don't do much, unless they are within a
### *doc-region*. The beginning of a doc-region is denoted by a doc-line
### whose first characters after the doc-symbol is
###
### <code>
### /// <doc region-name>
### </code>
###
### A doc region is ended one of three ways:
###
### 1. `&lt;/doc>` ends the active region.
### 2. `&lt;doc newname>` setting a new region name.
### 3. The end of the source file.
###
### When there is an active named region, any other doc lines will be
### appended (after stripping off the doc symbol itself) to the current
### doc region text.
###
### You can have multiple regions with the same name, in entirely separate
### parts of your source code. They will just be concatenated.
###
### Only one main doc region will be output by the `docdeep` program,
### specified with the `-d` command line argument. Any other doc-regions
### will not be included in the documention output of that run.
###
### However, one doc-region may *include* the text of another doc-region
### as follows:
###
### <code>
### /// <inc region-name>
### </code>
###
### ## Doc continuations and code regions
###
### If three dots follow the `doc` directive, like this:
###
### <code>
### /// <doc... region-name>
### </code>
###
### This causes *all* lines (until the end of the doc region) to be
### interpreted as Markdeep documentation, even it if doesn't start with
### the doc-symbol.
###
### Furthermore, denoting any region thusly:
### <code>
### /// <code>
### ...
### /// </code>
### </code>
###
### will designate the contents not only as a doc continuation, but also
### to be formatted as source code (mono space, syntax highlighted).
###
### ## API Explanations
###
### There is a special syntax for a common case: call-by-call explanations
### of API methods and their explanations. Of course, this may constitute
### the bulk of your auto-generated documentation. The two cases we are
### concerned about is *pre-code comments* and *post-code comments*.
###
### For pre-code comments, the contiguous comment region associated with
### a declaration immediately precedes the declaration. Such a comment
### set has its first line start with `///>`. For post-code comments,
### the documentaiton comments follows the code declaration, and this is
### designated by having its first line start with `///<`. I like to
### just remember that the `<` or `>` points in the direction of the code
### declaration that the comment applies to.
###
### This is perhaps best explained by example:
###
### <code>
### ///> Do the foo operation. Everybody knows what this is. You can write
### /// any comment you want, with full markdeep formatting! It applies
### /// to the declaration that will immediately follow this comment.
### float foo (float x, float y);
###
### void bar (int n);
### ///< The bar procedure. Note that with post-comments, you explain the
### /// function or method *after* the declaration itself.
### </code>
###
### This will generate the following output:
###
### <code>
### float foo (float x, float y);
### </code>
### Do the foo operation. Everybody knows what this is. You can write
### any comment you want, with full markdeep formatting! It applies
### to the declaration that will immediately follow this comment.
###
### <code>
### void bar (int n);
### </code>
### The bar procedure. Note that with post-comments, you explain the
### function or method *after* the declaration itself.
###
### -----------------------
###
### It is important to keep in mind that **this API explanation is extremely
### stupid**. The comment documentation is just a series of doc-lines with
### no break between them, whose *first* line starts with `///>' or `///>`
### (for pre-code and post-code docs, respectively). And the code that it
### documents is just the immediately preceding or following set of non-doc
### lines that contain *no* whitespace-only lines. There is no syntax
### parsing going on here -- it just takes those non-blank, non-doc lines,
### strips off any semicolons and any characters following the semicolon
### from each line in the block, and deletes anything in the whole block
### at or after the first opening brace (`{`) found in the block. Strangely
### enough, this is almost exactly what I want to document.
###
###
### Command line arguments
### ======================
###
### Run from the command line as follows:
###
### `$ python docdeep.py -d` *region* `-s` *style.css* `input1.h input2.cpp [...] > output.md.html`
###
### Arguments:
###
### `-d` *region*
### : Specifies the name of the doc-region to generate output for. This is
### required.
### `-s` *stylesheet*
### : This optional argument will specify which CSS style sheet to include a
### reference to.
###
### Any number of filenames may be specified. They will be processed in the
### order that they appear on the command line.
###
import sys
import re
import argparse
# pattern for beginning of special comment
docline_pattern = re.compile ('(^[ \t]*)((///)|(###))[<>]?([ \t]|$)(.*)')
doc_begin_pattern = re.compile ('(^[ \t]*)((///)|(###))[ ]*<doc(\.\.\.)?[ ]*(\w*)[ ]*>')
docendpattern = re.compile ('(^[ \t]*)((///)|(###))[ ]*</doc>')
api_precomment_pattern = re.compile ('(^[ \t]*)((///)|(###))>( )+( )?(.*)')
api_postcomment_pattern = re.compile ('(^[ \t]*)((///)|(###))<( )+( )?(.*)')
inc_pattern = re.compile ('(^[ \t]*)<inc[ ]+([^>]+)>')
code_pattern = re.compile ('(^[ \t]*)((///)|(###))[ ]*<code>')
codeend_pattern = re.compile ('(^[ \t]*)((///)|(###))[ ]*</code>')
trimbrace_pattern = re.compile ("([^{]*)")
trimsemi_pattern = re.compile ("([^;]*)")
blankline_pattern = re.compile ("^[ \t]*$")
region_name = '_'
alldocs = { '_' : '' }
DEBUG = False
# Utility: blob is a string (possibly containing many "lines" separated by
# '\n'). For each line of text in the blob, shave off the first `indent`
# characters. Then reassemble and return.
def shave_each_line (blob, indent) :
r = ''
lines = blob.split ('\n')
for line in lines :
r += line[indent:] + '\n'
# strip trailing newline unless the original blob had a trailing newline
if len(r) and r[-1] == '\n' and blob[-1] != '\n':
r = r[:-1]
return r
# Enumerated type for the state machine.
class LineType :
BLANK = 0
DOC = 2
NONDOC = 3
# Append this doc blob to the current region, and clear the blob
def flush_doc_blob (doc_blob) :
global alldocs, region_name
if len(doc_blob) :
alldocs[region_name] += doc_blob + '\n'
doc_blob = ''
def read_input (filename, file) :
global region_name, alldocs
doc_cont_mode = False
post_api_mode = False
pre_api_mode = False
indent = 0 # Amount of indentation we saw on the liast doc line
lines = file.read().splitlines()
code_blob = '' # Running set of contiguous non-doc, non-blank lines
doc_blob = '' # Running set of contiguous doc lines
# state machine
line_type = LineType.BLANK
last_line_type = LineType.BLANK
for line in lines :
# Figure out what type of line we're on, and remember what type
# of line we saw last.
last_line_type = line_type
if blankline_pattern.match(line) :
line_type = LineType.BLANK
elif docline_pattern.match(line) :
line_type = LineType.DOC
else :
line_type = LineType.NONDOC
# print ('<!-- LINE----- ', line_type, line, ' -->\n')
# Not a doc line, but we're in "continuation mode": append
# (unindented) to the doc blob.
if line_type != LineType.DOC and doc_cont_mode :
doc_blob += line[indent:] + '\n'
if DEBUG :
alldocs[region_name] += '<!-- CONT ' + line[:35] + ' -->\n'
continue
# Blank line, not in continuation mode
if line_type == LineType.BLANK :
if DEBUG and last_line_type != LineType.BLANK :
alldocs[region_name] += '<!-- BLANK -->\n'
# FIXME: does this end a post-declaration API doc?
if pre_api_mode : # this blank ends a pre-api comment
continue # ...keep reading
# If this line ends a post-api comment, output the code blob
if post_api_mode :
if DEBUG :
alldocs[region_name] += ' <!-- blank ended post-api -->\n'
# Trim everything past the first ; or { from the code blob
alllines = code_blob.split('\n')
# code_blob = ''
new_code_blob = ''
for oneline in alllines :
m = trimsemi_pattern.search (oneline)
oneline = m.group(1)
new_code_blob += oneline + '\n'
new_code_blob = new_code_blob.rstrip(' \n\r')
m = trimbrace_pattern.match(new_code_blob)
alldocs[region_name] += ('~~~C\n' +
shave_each_line(m.group(1),indent) +
'\n~~~\n')
post_api_mode = False
# If this line ends a doc blob, output it
if len(doc_blob) :
alldocs[region_name] += doc_blob + '\n'
doc_blob = ''
# Blank lines clear the code blob
code_blob = ''
continue
# Non-blank, non-doc line: append to code blob and move on.
if line_type == LineType.NONDOC :
if DEBUG :
alldocs[region_name] += '<!-- NONDOC ' + line[:35] + ' -->\n'
code_blob += line + '\n'
continue
# Remaining cases are all doc lines!
# Any doc line resets the pre-doc-symbol indentation level
m = docline_pattern.match(line)
indent = len(m.group(1))
# Handle <doc> and <doc...> : start of new doc section
m = doc_begin_pattern.match(line)
if m :
flush_doc_blob (doc_blob)
doc_blob = ''
# If it led with <doc...> it also starts continuation mode
doc_cont_mode = (m.group(5) == '...')
# The <doc> directive gave the region name.
r = m.group(6)
r.strip()
if r == '' :
r = '_'
if DEBUG :
alldocs[region_name] += '<!-- DOCBEGIN ' + r + ' -->\n'
region_name = r
if not (region_name in alldocs) :
alldocs[region_name] = ''
continue
#
# Handle </doc>
m = docendpattern.match(line)
if m :
if DEBUG :
alldocs[region_name] += '<!-- DOCEND ' + region_name + '-->\n'
flush_doc_blob (doc_blob)
doc_blob = ''
doc_cont_mode = False
region_name = '_'
continue
#
# Handle start of post-declaration API comment
m = api_postcomment_pattern.match(line)
if m :
if DEBUG :
alldocs[region_name] += '<!-- start post-decl api ' + line[:35] + '-->\n'
flush_doc_blob (doc_blob)
doc_blob = ''
# Deduce indentation level
indent = len(m.group(1))
post_api_mode = True
remainder = m.group(7)
doc_blob += remainder + '\n'
continue
#
# Handle start of pre-declaration API comment
m = api_precomment_pattern.match(line)
if m :
flush_doc_blob (doc_blob)
doc_blob = ''
indent = len(m.group(1))
post_api_mode = True
remainder = m.group(7)
doc_blob += remainder + '\n'
continue
#
# Handle code section <code> ... </code>
m = code_pattern.match(line)
if m :
flush_doc_blob (doc_blob)
doc_blob = ''
if DEBUG :
doc_blob += '<!-- start code in '+ region_name+ '-->\n'
indent = len(m.group(1))
doc_blob += '<script type="preformatted">\n~~~C\n'
doc_cont_mode = True
continue
if codeend_pattern.match(line) :
doc_cont_mode = False
doc_blob += '~~~\n</script>\n'
if DEBUG :
doc_blob += '<!-- end code in '+ region_name+ '-->\n'
flush_doc_blob (doc_blob)
doc_blob = ''
continue
#
# Last case: just a continuing doc line
m = docline_pattern.match (line)
if m :
if DEBUG :
alldocs[region_name] += '<!-- doc cont ' + line[:35] + ' -->\n'
contents = m.group(6)
doc_blob += contents + '\n'
continue
print ('<!-- REMAINING CASE:', line, '-->\n')
flush_doc_blob (doc_blob)
region_name = '_'
def output_blob (blob) :
for line in blob.splitlines() :
m = inc_pattern.match (line)
if m and (m.group(2) in alldocs) :
# print ('Want to include', m.group(2))
output_blob (alldocs[m.group(2)])
else :
print (line)
parser = argparse.ArgumentParser (prog='docdeep',
description='Turn source comments into markdeep document')
parser.add_argument ('-d', dest='docname', default='main',
help='Name of documentation (default: "main")')
parser.add_argument ('-s', dest='stylesheet', default='',
help='Name of style sheet (default: "")')
parser.add_argument ('--debug', dest='DEBUG', action='store_const',
const=True, default=False)
parser.add_argument ('filenames', nargs='+')
# parser.add_argument ('-o', dest='output_filename', nargs=1,
# help='Output filename (default: stdout)')
args = parser.parse_args()
DEBUG = args.DEBUG
for filename in args.filenames :
with open(filename) as file:
read_input (filename, file)
print ('<meta charset="utf-8">\n')
if args.docname in alldocs :
output_blob (alldocs[args.docname])
else :
print ("Ick! could not find docs for", args.docname)
print ('<!-- Markdeep: --><style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style><script src="markdeep.min.js"></script><script src="https://casual-effects.com/markdeep/latest/markdeep.min.js?"></script><script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>')
if args.stylesheet :
print ('<link rel="stylesheet" href="{}">'.format (args.stylesheet))
+1 -1
View File
@@ -1,4 +1,4 @@
{
global: *OSL*; test_shade; *osl*imageio*; *osl_input_extensions;
local: osl_*; *;
local: osl_*; *pvt*; *;
};
@@ -26,6 +26,7 @@ brew install ilmbase openexr
brew install opencolorio partio
brew install freetype libpng
brew install llvm${LLVMBREWVER}
brew install qt
#brew install homebrew/science/hdf5 --with-threadsafe
#brew install field3d webp ffmpeg openjpeg opencv
echo ""
+17 -5
View File
@@ -21,6 +21,7 @@ option (CLANG_TIDY "Enable clang-tidy" OFF)
set (CLANG_TIDY_CHECKS "-*" CACHE STRING "clang-tidy checks to perform")
set (CLANG_TIDY_ARGS "" CACHE STRING "clang-tidy args")
option (CLANG_TIDY_FIX "Have clang-tidy fix source" OFF)
set (GLIBCXX_USE_CXX11_ABI "" CACHE STRING "For gcc, use the new C++11 library ABI (0|1)")
# Figure out which compiler we're using
@@ -64,8 +65,11 @@ endif ()
# turn on more detailed warnings and consider warnings as errors
if (NOT MSVC)
add_definitions ("-Wall")
if (STOP_ON_WARNING)
if (STOP_ON_WARNING OR DEFINED ENV{CI})
add_definitions ("-Werror")
# N.B. Force CI builds (Travis defines $CI) to use -Werror, even if
# STOP_ON_WARNING has been switched off by default, which we may do
# in release branches.
endif ()
endif ()
@@ -193,6 +197,18 @@ if (USE_LIBCPLUSPLUS AND CMAKE_COMPILER_IS_CLANG)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif ()
# GCC 5+: honor build-time option for whether or not to use new string ABI.
# FIXME: In theory, this should also be needed for clang, if compiling with
# the gcc libstdc++ toolchain. In practice, I could not get things to build
# with clang properly when using this option, and I haven't yet seen a case
# where it's needed. We can return to this and fix for clang if it becomes a
# legit problem later.
if (CMAKE_COMPILER_IS_GNUCC AND NOT ${GCC_VERSION} VERSION_LESS 5.0)
if (NOT ${GLIBCXX_USE_CXX11_ABI} STREQUAL "")
add_definitions ("-D_GLIBCXX_USE_CXX11_ABI=${GLIBCXX_USE_CXX11_ABI}")
endif ()
endif ()
# SIMD and machine architecture options
set (SIMD_COMPILE_FLAGS "")
@@ -340,8 +356,4 @@ endif ()
if (DEFINED ENV{TRAVIS} OR DEFINED ENV{APPVEYOR} OR DEFINED ENV{CI})
add_definitions ("-D${PROJECT_NAME}_CI=1" "-DBUILD_CI=1")
if (WIN32)
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
endif ()
endif ()
+90 -29
View File
@@ -15,8 +15,11 @@ if (NOT VERBOSE)
set (PugiXML_FIND_QUIETLY TRUE)
set (PythonInterp_FIND_QUIETLY true)
set (PythonLibs_FIND_QUIETLY true)
set (Qt5_FIND_QUIETLY true)
set (Threads_FIND_QUIETLY true)
set (ZLIB_FIND_QUIETLY true)
set (CUDA_FIND_QUIETLY true)
set (OptiX_FIND_QUIETLY true)
endif ()
@@ -52,7 +55,7 @@ endif ()
###########################################################################
# OpenImageIO
find_package (OpenImageIO 1.7 REQUIRED)
find_package (OpenImageIO 1.8.5 REQUIRED)
include_directories ("${OPENIMAGEIO_INCLUDE_DIR}")
link_directories ("${OPENIMAGEIO_LIBRARY_DIRS}")
message (STATUS "Using OpenImageIO ${OPENIMAGEIO_VERSION}")
@@ -64,7 +67,7 @@ message (STATUS "Using OpenImageIO ${OPENIMAGEIO_VERSION}")
###########################################################################
# LLVM library setup
find_package (LLVM 3.5 REQUIRED)
find_package (LLVM 4.0 REQUIRED)
# ensure include directory is added (in case of non-standard locations
include_directories (BEFORE SYSTEM "${LLVM_INCLUDES}")
@@ -89,10 +92,6 @@ if (NOT Boost_FIND_QUIETLY)
message (STATUS "BOOST_ROOT ${BOOST_ROOT}")
endif ()
if (NOT DEFINED Boost_ADDITIONAL_VERSIONS)
set (Boost_ADDITIONAL_VERSIONS "1.63" "1.62" "1.61" "1.60"
"1.59" "1.58" "1.57" "1.56" "1.55")
endif ()
if (LINKSTATIC)
set (Boost_USE_STATIC_LIBS ON)
endif ()
@@ -101,8 +100,7 @@ set (Boost_COMPONENTS system thread)
if (NOT USE_STD_REGEX)
list (APPEND Boost_COMPONENTS regex)
endif ()
if (CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_APPLECLANG OR
${LLVM_VERSION} VERSION_LESS 3.6)
if (CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_APPLECLANG)
set (_CLANG_PREPROCESSOR_CAN_WORK ON)
endif ()
if (GCC_VERSION)
@@ -110,17 +108,6 @@ if (GCC_VERSION)
set (_CLANG_PREPROCESSOR_CAN_WORK ON)
endif ()
endif ()
if (${LLVM_VERSION} VERSION_LESS 3.9)
# Bug in old LLVM creates some linkage problems we've seen involving
# some singleton globals that are duplicated when we include both
# the clang libs we need for the preprocessing as well as certain
# LLVM support libraries we also need, triggering assertions.
# See this for description of the issue:
# http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20140203/203968.html
# Sweep under the rug by falling back to boost wave when using older
# LLVM (it seems fixed and no longer triggers for 3.9+).
set (_CLANG_PREPROCESSOR_CAN_WORK OFF)
endif ()
if (USE_BOOST_WAVE OR (NOT CLANG_LIBRARIES)
OR (NOT _CLANG_PREPROCESSOR_CAN_WORK))
# N.B. Using clang for preprocessing seems to work when using clang,
@@ -186,15 +173,89 @@ endif (USE_PARTIO)
###########################################################################
# Pugixml setup. Normally we just use the version bundled with oiio, but
# some linux distros are quite particular about having separate packages so we
# allow this to be overridden to use the distro-provided package if desired.
if (USE_EXTERNAL_PUGIXML)
find_package (PugiXML REQUIRED)
# insert include path to pugixml first, to ensure that the external
# pugixml is found, and not the one in OIIO's include directory.
include_directories (BEFORE "${PUGIXML_INCLUDE_DIR}")
add_definitions ("-DUSE_EXTERNAL_PUGIXML")
endif()
# Pugixml setup. Prefer a system install, but note that FindPugiXML.cmake
# will look in the OIIO distribution if it's not found on the system.
find_package (PugiXML REQUIRED)
include_directories (BEFORE "${PUGIXML_INCLUDE_DIR}")
# end Pugixml setup
###########################################################################
###########################################################################
# Qt setup
if (USE_QT)
set (qt5_modules Core Gui Widgets)
# if (USE_OPENGL)
# list (APPEND qt5_modules OpenGL)
# endif ()
find_package (Qt5 COMPONENTS ${qt5_modules})
endif ()
if (USE_QT AND Qt5_FOUND)
if (NOT Qt5_FIND_QUIETLY)
message (STATUS "Qt5_FOUND=${Qt5_FOUND}")
endif ()
else ()
message (STATUS "No Qt5 -- skipping components that need Qt5.")
if (USE_QT AND NOT Qt5_FOUND AND APPLE)
message (STATUS "If you think you installed qt5 with Homebrew and it still doesn't work,")
message (STATUS "try: export PATH=/usr/local/opt/qt5/bin:$PATH")
endif ()
endif ()
# end Qt setup
###########################################################################
###########################################################################
# CUDA setup
if (USE_CUDA OR USE_OPTIX)
if (NOT CUDA_TOOLKIT_ROOT_DIR AND NOT $ENV{CUDA_TOOLKIT_ROOT_DIR} STREQUAL "")
set (CUDA_TOOLKIT_ROOT_DIR $ENV{CUDA_TOOLKIT_ROOT_DIR})
endif ()
if (NOT CUDA_FIND_QUIETLY OR NOT OptiX_FIND_QUIETLY)
message (STATUS "CUDA_TOOLKIT_ROOT_DIR = ${CUDA_TOOLKIT_ROOT_DIR}")
endif ()
find_package (CUDA 8.0 REQUIRED)
set (CUDA_INCLUDE_DIR ${CUDA_TOOLKIT_ROOT_DIR}/include)
include_directories (BEFORE "${CUDA_INCLUDE_DIR}")
message (STATUS "CUDA version = ${CUDA_VERSION}")
if (NOT CUDA_FIND_QUIETLY OR NOT OptiX_FIND_QUIETLY)
message (STATUS "CUDA includes = ${CUDA_INCLUDE_DIR}")
message (STATUS "CUDA libraries = ${CUDA_LIBRARIES}")
endif ()
STRING (FIND ${LLVM_TARGETS} "NVPTX" nvptx_index)
if (NOT ${nvptx_index} GREATER -1)
message (FATAL_ERROR "NVTPX target is not available in the provided LLVM build")
endif()
if (${CUDA_VERSION_MAJOR} GREATER 8 AND ${LLVM_VERSION} LESS 6)
message (FATAL_ERROR "CUDA ${CUDA_VERSION} requires LLVM 6.0 or greater")
endif ()
set (CUDA_LIB_FLAGS "--cuda-path=${CUDA_TOOLKIT_ROOT_DIR}")
endif ()
# end CUDA setup
###########################################################################
###########################################################################
# OptiX setup
if (USE_OPTIX)
find_package (OptiX 5.1 REQUIRED)
include_directories (BEFORE "${OPTIX_INCLUDE_DIR}")
if (NOT USE_LLVM_BITCODE OR NOT USE_FAST_MATH)
message (FATAL_ERROR "Enabling OptiX requires USE_LLVM_BITCODE=1 and USE_FAST_MATH=1")
endif ()
endif ()
# end OptiX setup
###########################################################################
+31 -56
View File
@@ -1,8 +1,7 @@
# LG's macros for using flex and bison.
# Merely including this file will set FLEX_EXECUTABLE and BISON_EXECUTABLE
# to the locations of 'flex' and 'bison' on the system, and leave them
# undefined if those programs were not found.
# If both are found, there will also be a macro defined:
# Merely including this file will require flex and bison to be found.
#
# The main purpose is to define the macro FLEX_BISON:
# FLEX_BISON ( flexsrc bisonsrc srclist compiler_headers )
# where
# flexsrc = the name of the .l file
@@ -14,72 +13,48 @@
# for the .y and .l files.
IF (NOT FLEX_EXECUTABLE)
if (NOT Flex_FIND_QUIETLY)
MESSAGE (STATUS "Looking for flex")
endif ()
FIND_PROGRAM (FLEX_EXECUTABLE flex)
IF (FLEX_EXECUTABLE)
if (NOT Flex_FIND_QUIETLY)
MESSAGE (STATUS "Looking for flex -- ${FLEX_EXECUTABLE}")
endif ()
ENDIF (FLEX_EXECUTABLE)
ENDIF (NOT FLEX_EXECUTABLE)
find_package (BISON REQUIRED)
find_package (FLEX REQUIRED)
IF (NOT BISON_EXECUTABLE)
if (NOT Bison_FIND_QUIETLY)
MESSAGE (STATUS "Looking for bison")
endif ()
FIND_PROGRAM (BISON_EXECUTABLE bison)
IF (BISON_EXECUTABLE)
if (NOT Bison_FIND_QUIETLY)
MESSAGE (STATUS "Looking for bison -- ${BISON_EXECUTABLE}")
endif ()
ENDIF (BISON_EXECUTABLE)
ENDIF (NOT BISON_EXECUTABLE)
IF ( FLEX_EXECUTABLE AND BISON_EXECUTABLE )
MACRO ( FLEX_BISON flexsrc bisonsrc prefix srclist compiler_headers )
if ( FLEX_EXECUTABLE AND BISON_EXECUTABLE )
macro ( FLEX_BISON flexsrc bisonsrc prefix srclist compiler_headers )
if (VERBOSE)
MESSAGE (STATUS "FLEX_BISON flex=${flexsrc} bison=${bisonsrc} prefix=${prefix}")
message (STATUS "FLEX_BISON flex=${flexsrc} bison=${bisonsrc} prefix=${prefix}")
endif ()
#MESSAGE (STATUS " src ${CMAKE_CURRENT_SOURCE_DIR}")
#MESSAGE (STATUS " bin ${CMAKE_CURRENT_BINARY_DIR}")
GET_FILENAME_COMPONENT ( bisonsrc_we ${bisonsrc} NAME_WE )
SET ( bisonoutputcxx "${CMAKE_CURRENT_BINARY_DIR}/${bisonsrc_we}.cpp" )
SET ( bisonoutputh "${CMAKE_CURRENT_BINARY_DIR}/${bisonsrc_we}.h" )
# MESSAGE (STATUS " bison output ${bisonoutputcxx} ${bisonoutputh}")
get_filename_component ( bisonsrc_we ${bisonsrc} NAME_WE )
set ( bisonoutputcxx "${CMAKE_CURRENT_BINARY_DIR}/${bisonsrc_we}.cpp" )
set ( bisonoutputh "${CMAKE_CURRENT_BINARY_DIR}/${bisonsrc_we}.h" )
GET_FILENAME_COMPONENT ( flexsrc_we ${flexsrc} NAME_WE )
SET ( flexoutputcxx "${CMAKE_CURRENT_BINARY_DIR}/${flexsrc_we}.cpp" )
# MESSAGE (STATUS " flex output ${flexoutputcxx}")
SET ( ${srclist} ${${srclist}} ${bisonoutputcxx} ${flexoutputcxx} )
# MESSAGE (STATUS " src list now ${${srclist}}")
# MESSAGE (STATUS " compiler headers = ${${compiler_headers}}")
get_filename_component ( flexsrc_we ${flexsrc} NAME_WE )
set ( flexoutputcxx "${CMAKE_CURRENT_BINARY_DIR}/${flexsrc_we}.cpp" )
set ( ${srclist} ${${srclist}} ${bisonoutputcxx} ${flexoutputcxx} )
# Be really sure that we prefer the FlexLexer.h that comes with
# the flex binary we're using, not some other one in the system.
GET_FILENAME_COMPONENT ( FLEX_UP ${FLEX_EXECUTABLE} PATH )
GET_FILENAME_COMPONENT ( FLEX_UP_UP ${FLEX_UP} PATH )
SET ( FLEX_INCLUDE_DIR "${FLEX_UP_UP}/include" )
get_filename_component ( FLEX_UP ${FLEX_EXECUTABLE} PATH )
get_filename_component ( FLEX_UP_UP ${FLEX_UP} PATH )
set ( FLEX_INCLUDE_DIR "${FLEX_UP_UP}/include" )
if (VERBOSE)
MESSAGE (STATUS "Flex include dir = ${FLEX_INCLUDE_DIR}")
message (STATUS "Flex include dir = ${FLEX_INCLUDE_DIR}")
endif ()
INCLUDE_DIRECTORIES ( ${FLEX_INCLUDE_DIR} )
include_directories ( ${FLEX_INCLUDE_DIR} )
INCLUDE_DIRECTORIES ( ${CMAKE_CURRENT_BINARY_DIR} )
INCLUDE_DIRECTORIES ( ${CMAKE_CURRENT_SOURCE_DIR} )
ADD_CUSTOM_COMMAND ( OUTPUT ${bisonoutputcxx}
# include_directories ( ${CMAKE_CURRENT_BINARY_DIR} )
include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} )
add_custom_command ( OUTPUT ${bisonoutputcxx}
COMMAND ${BISON_EXECUTABLE} -dv -p ${prefix} -o ${bisonoutputcxx} "${CMAKE_CURRENT_SOURCE_DIR}/${bisonsrc}"
MAIN_DEPENDENCY ${bisonsrc}
DEPENDS ${${compiler_headers}}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )
ADD_CUSTOM_COMMAND ( OUTPUT ${flexoutputcxx}
COMMAND ${FLEX_EXECUTABLE} -o ${flexoutputcxx} "${CMAKE_CURRENT_SOURCE_DIR}/${flexsrc}"
if ( WINDOWS )
set ( FB_WINCOMPAT --wincompat )
else ()
set ( FB_WINCOMPAT )
endif ()
add_custom_command ( OUTPUT ${flexoutputcxx}
COMMAND ${FLEX_EXECUTABLE} ${FB_WINCOMPAT} -o ${flexoutputcxx} "${CMAKE_CURRENT_SOURCE_DIR}/${flexsrc}"
MAIN_DEPENDENCY ${flexsrc}
DEPENDS ${${compiler_headers}}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )
ENDMACRO ()
ENDIF ()
endmacro ()
endif ()
+8 -19
View File
@@ -8,6 +8,7 @@
# LLVM_SYSTEM_LIBRARIES - additional libraries needed by LLVM
# LLVM_DIRECTORY - If not already set, the root of the LLVM install
# LLVM_LIB_DIR - where to find llvm libs
# LLVM_TARGETS - List of available LLVM targets
# CLANG_LIBRARIES - list of libraries for clang components (optional,
# those may not be found)
#
@@ -48,18 +49,13 @@ execute_process (COMMAND ${LLVM_CONFIG} --libdir
execute_process (COMMAND ${LLVM_CONFIG} --includedir
OUTPUT_VARIABLE LLVM_INCLUDES
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (NOT ${LLVM_VERSION} VERSION_LESS 3.8)
execute_process (COMMAND ${LLVM_CONFIG} --system-libs
OUTPUT_VARIABLE LLVM_SYSTEM_LIBRARIES
OUTPUT_STRIP_TRAILING_WHITESPACE)
else ()
# Older LLVM did not have llvm-config --system-libs, but we know that
# on Linux, we'll need curses.
find_package (Curses)
if (CURSES_FOUND)
list (APPEND LLVM_SYSTEM_LIBRARIES ${CURSES_LIBRARIES})
endif ()
endif ()
execute_process (COMMAND ${LLVM_CONFIG} --targets-built
OUTPUT_VARIABLE LLVM_TARGETS
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process (COMMAND ${LLVM_CONFIG} --system-libs
OUTPUT_VARIABLE LLVM_SYSTEM_LIBRARIES
OUTPUT_STRIP_TRAILING_WHITESPACE)
string (REPLACE " " ";" LLVM_SYSTEM_LIBRARIES "${LLVM_SYSTEM_LIBRARIES}")
find_library ( LLVM_LIBRARY
NAMES LLVM-${LLVM_VERSION} LLVM
@@ -68,7 +64,6 @@ find_library ( LLVM_MCJIT_LIBRARY
NAMES LLVMMCJIT
PATHS ${LLVM_LIB_DIR})
foreach (COMPONENT clangFrontend clangDriver clangSerialization
clangParse clangSema clangAnalysis clangAST clangBasic
clangEdit clangLex)
@@ -81,12 +76,6 @@ foreach (COMPONENT clangFrontend clangDriver clangSerialization
endforeach ()
# if (NOT LLVM_LIBRARY)
# execute_process (COMMAND ${LLVM_CONFIG} --libfiles engine
# OUTPUT_VARIABLE LLVM_LIBRARIES
# OUTPUT_STRIP_TRAILING_WHITESPACE)
# endif ()
# shared llvm library may not be available, this is not an error if we use LLVM_STATIC.
if ((LLVM_LIBRARY OR LLVM_LIBRARIES OR LLVM_STATIC) AND LLVM_INCLUDES AND LLVM_DIRECTORY AND LLVM_LIB_DIR)
if (LLVM_STATIC)
+45 -30
View File
@@ -8,14 +8,9 @@
# OPENEXR_VERSION OpenEXR version (accurate for >= 2.0.0,
# otherwise will just guess 1.6.1)
#
# Special inputs:
# OPENEXR_CUSTOM_INCLUDE_DIR - custom location of headers
# OPENEXR_CUSTOM_LIB_DIR - custom location of libraries
# OPENEXR_CUSTOM_LIB_PREFIX - special snowflake library prefix
# OPENEXR_CUSTOM_LIB_SUFFIX - special snowflake library suffix
#
# Other standarnd issue macros
# Other standard issue macros
include (FindPackageHandleStandardArgs)
include (SelectLibraryConfigurations)
@@ -27,17 +22,31 @@ if (CMAKE_USE_PTHREADS_INIT)
set (ILMBASE_PTHREADS ${CMAKE_THREAD_LIBS_INIT})
endif ()
# Attempt to find OpenEXR with pkgconfig
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
if (NOT ILMBASE_ROOT_DIR)
pkg_check_modules(_ILMBASE QUIET IlmBase>=2.0.0)
endif ()
if (NOT OPENEXR_ROOT_DIR)
pkg_check_modules(_OPENEXR QUIET OpenEXR>=2.0.0)
endif ()
endif (PKG_CONFIG_FOUND)
# List of likely places to find the headers -- note priority override of
# OPENEXR_CUSTOM_INCLUDE_DIR and ${OPENEXR_HOME}/include.
# ${OPENEXR_ROOT_DIR}/include.
# ILMBASE is needed in case ilmbase an openexr are installed in separate
# directories, like NixOS does
set (GENERIC_INCLUDE_PATHS
${OPENEXR_CUSTOM_INCLUDE_DIR}
${OPENEXR_HOME}/include
${ILMBASE_HOME}/include
${OPENEXR_ROOT_DIR}/include
$ENV{OPENEXR_ROOT_DIR}/include
${ILMBASE_ROOT_DIR}/include
$ENV{ILMBASE_ROOT_DIR}/include
${_ILMBASE_INCLUDEDIR}
${_OPENEXR_INCLUDEDIR}
/usr/local/include
/usr/include
/usr/include/${CMAKE_LIBRARY_ARCHITECTURE}
/usr/local/include
/sw/include
/opt/local/include )
@@ -46,14 +55,20 @@ set (GENERIC_INCLUDE_PATHS
# This seems to be the most robust way I can find to not get confused when
# both system and custom libraries are present.
find_path (ILMBASE_INCLUDE_PATH OpenEXR/IlmBaseConfig.h
PATHS ${GENERIC_INCLUDE_PATHS} NO_DEFAULT_PATH)
PATHS ${ILMBASE_INCLUDE_DIR} ${OPENEXR_INCLUDE_DIR}
${GENERIC_INCLUDE_PATHS} NO_DEFAULT_PATH)
find_path (ILMBASE_INCLUDE_PATH OpenEXR/IlmBaseConfig.h)
find_path (OPENEXR_INCLUDE_PATH OpenEXR/OpenEXRConfig.h
PATHS ${GENERIC_INCLUDE_PATHS} NO_DEFAULT_PATH)
PATHS ${OPENEXR_INCLUDE_DIR}
${GENERIC_INCLUDE_PATHS} NO_DEFAULT_PATH)
find_path (OPENEXR_INCLUDE_PATH OpenEXR/OpenEXRConfig.h)
# Try to figure out version number
if (EXISTS "${OPENEXR_INCLUDE_PATH}/OpenEXR/ImfMultiPartInputFile.h")
if (DEFINED _OPENEXR_VERSION AND NOT "${_OPENEXR_VERSION}" STREQUAL "")
set (OPENEXR_VERSION "${_OPENEXR_VERSION}")
string (REGEX REPLACE "([0-9]+)\\.[0-9\\.]+" "\\1" OPENEXR_VERSION_MAJOR "${_OPENEXR_VERSION}")
string (REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.[0-9]+)?" "\\1" OPENEXR_VERSION_MINOR "${_OPENEXR_VERSION}")
elseif (EXISTS "${OPENEXR_INCLUDE_PATH}/OpenEXR/ImfMultiPartInputFile.h")
# Must be at least 2.0
file(STRINGS "${OPENEXR_INCLUDE_PATH}/OpenEXR/OpenEXRConfig.h" TMP REGEX "^#define OPENEXR_VERSION_STRING .*$")
string (REGEX MATCHALL "[0-9]+[.0-9]+" OPENEXR_VERSION ${TMP})
@@ -70,21 +85,24 @@ endif ()
# List of likely places to find the libraries -- note priority override of
# OPENEXR_CUSTOM_LIB_DIR and ${OPENEXR_HOME}/lib.
set (GENERIC_LIBRARY_PATHS
${OPENEXR_CUSTOM_LIB_DIR}
${OPENEXR_HOME}/lib
${ILMBASE_HOME}/lib
# ${OPENEXR_ROOT_DIR}/lib.
set (GENERIC_LIBRARY_PATHS
${OPENEXR_ROOT_DIR}/lib
${ILMBASE_ROOT_DIR}/lib
${OPENEXR_INCLUDE_PATH}/../lib
${ILMBASE_INCLUDE_PATH}/../lib
/usr/lib
/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}
${_ILMBASE_LIBDIR}
${_OPENEXR_LIBDIR}
/usr/local/lib
/usr/local/lib/${CMAKE_LIBRARY_ARCHITECTURE}
/usr/lib
/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}
/sw/lib
/opt/local/lib
$ENV{PROGRAM_FILES}/OpenEXR/lib/static )
# message (STATUS "Generic lib paths: ${GENERIC_LIBRARY_PATHS}")
# Handle request for static libs by altering CMAKE_FIND_LIBRARY_SUFFIXES.
# We will restore it at the end of this file.
set (_openexr_orig_suffixes ${CMAKE_FIND_LIBRARY_SUFFIXES})
@@ -104,24 +122,21 @@ set (_openexr_components IlmThread IlmImf Imath Iex Half)
foreach (COMPONENT ${_openexr_components})
string (TOUPPER ${COMPONENT} UPPERCOMPONENT)
# First try with the version embedded
set (FULL_COMPONENT_NAME ${OPENEXR_CUSTOM_LIB_PREFIX}${COMPONENT}-${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR}${OPENEXR_CUSTOM_LIB_SUFFIX})
set (FULL_COMPONENT_NAME ${COMPONENT}-${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR})
find_library (OPENEXR_${UPPERCOMPONENT}_LIBRARY ${FULL_COMPONENT_NAME}
PATHS ${GENERIC_LIBRARY_PATHS} NO_DEFAULT_PATH)
PATHS ${OPENEXR_LIBRARY_DIR} $ENV{OPENEXR_LIBRARY_DIR}
${GENERIC_LIBRARY_PATHS} NO_DEFAULT_PATH)
# Again, with no directory restrictions
find_library (OPENEXR_${UPPERCOMPONENT}_LIBRARY ${FULL_COMPONENT_NAME})
# Try again without the version
set (FULL_COMPONENT_NAME ${OPENEXR_CUSTOM_LIB_PREFIX}${COMPONENT}${OPENEXR_CUSTOM_LIB_SUFFIX})
set (FULL_COMPONENT_NAME ${COMPONENT})
find_library (OPENEXR_${UPPERCOMPONENT}_LIBRARY ${FULL_COMPONENT_NAME}
PATHS ${GENERIC_LIBRARY_PATHS} NO_DEFAULT_PATH)
PATHS ${OPENEXR_LIBRARY_DIR} $ENV{OPENEXR_LIBRARY_DIR}
${GENERIC_LIBRARY_PATHS} NO_DEFAULT_PATH)
# One more time, with no restrictions
find_library (OPENEXR_${UPPERCOMPONENT}_LIBRARY ${FULL_COMPONENT_NAME})
endforeach ()
#Half usually has no suffix
find_library (OPENEXR_HALF_LIBRARY ${OPENEXR_CUSTOM_LIB_PREFIX}Half
PATHS ${GENERIC_LIBRARY_PATHS} NO_DEFAULT_PATH)
find_library (OPENEXR_HALF_LIBRARY ${OPENEXR_CUSTOM_LIB_PREFIX}Half)
# Set the FOUND, INCLUDE_DIR, and LIBRARIES variables.
if (ILMBASE_INCLUDE_PATH AND OPENEXR_INCLUDE_PATH AND
OPENEXR_IMATH_LIBRARY AND OPENEXR_ILMIMF_LIBRARY AND
+25 -13
View File
@@ -1,4 +1,13 @@
###########################################################################
# OpenImageIO https://www.openimageio.org
# Copyright 2008-2018 Larry Gritz et al. All rights reserved.
# BSD 3-clause license:
# https://github.com/OpenImageIO/oiio/blob/master/LICENSE
# For an up-to-date version of this file, see:
# https://github.com/OpenImageIO/oiio/blob/master/src/cmake/Modules/FindOpenImageIO.cmake
#
###########################################################################
#
# CMake module to find OpenImageIO
#
# This module will set
@@ -10,35 +19,38 @@
# OPENIMAGEIO_VERSION_MAJOR Version major number
# OPENIMAGEIO_VERSION_MINOR Version minor number
# OPENIMAGEIO_VERSION_PATCH Version minor patch
# OIIOTOOL_BIN Path to oiiotool executable
#
# Special inputs:
# OPENIMAGEIOHOME - custom "prefix" location of OIIO installation
# (expecting bin, lib, include subdirectories)
# OPENIMAGEIO_ROOT_DIR - custom "prefix" location of OIIO installation
# (expecting bin, lib, include subdirectories)
# OpenImageIO_FIND_QUIETLY - if set, print minimal console output
#
###########################################################################
# If 'OPENIMAGEHOME' not set, use the env variable of that name if available
if (NOT OPENIMAGEIOHOME AND NOT $ENV{OPENIMAGEIOHOME} STREQUAL "")
set (OPENIMAGEIOHOME $ENV{OPENIMAGEIOHOME})
# If 'OPENIMAGE_HOME' not set, use the env variable of that name if available
if (NOT OPENIMAGEIO_ROOT_DIR AND NOT $ENV{OPENIMAGEIO_ROOT_DIR} STREQUAL "")
set (OPENIMAGEIO_ROOT_DIR $ENV{OPENIMAGEIO_ROOT_DIR})
endif ()
if (NOT OpenImageIO_FIND_QUIETLY)
message ( STATUS "OPENIMAGEIOHOME = ${OPENIMAGEIOHOME}" )
message ( STATUS "OPENIMAGEIO_ROOT_DIR = ${OPENIMAGEIO_ROOT_DIR}" )
endif ()
find_library ( OPENIMAGEIO_LIBRARY
NAMES OpenImageIO
HINTS ${OPENIMAGEIOHOME}/lib
HINTS ${OPENIMAGEIO_ROOT_DIR}/lib
PATH_SUFFIXES lib64 lib
PATHS "${OPENIMAGEIOHOME}/lib" )
PATHS "${OPENIMAGEIO_ROOT_DIR}/lib" )
find_path ( OPENIMAGEIO_INCLUDE_DIR
NAMES OpenImageIO/imageio.h
HINTS ${OPENIMAGEIOHOME}/include
HINTS ${OPENIMAGEIO_ROOT_DIR}/include
PATH_SUFFIXES include )
find_program ( OPENIMAGEIO_BIN
NAMES oiiotool
HINTS ${OPENIMAGEIOHOME}/bin
find_program ( OIIOTOOL_BIN
NAMES oiiotool oiiotool.exe
HINTS ${OPENIMAGEIO_ROOT_DIR}/bin
PATH_SUFFIXES bin )
# Try to figure out version number
@@ -60,7 +72,7 @@ if (NOT OpenImageIO_FIND_QUIETLY)
message ( STATUS "OpenImageIO includes = ${OPENIMAGEIO_INCLUDE_DIR}" )
message ( STATUS "OpenImageIO libraries = ${OPENIMAGEIO_LIBRARIES}" )
message ( STATUS "OpenImageIO library_dirs = ${OPENIMAGEIO_LIBRARY_DIRS}" )
message ( STATUS "OpenImageIO bin = ${OPENIMAGEIO_BIN}" )
message ( STATUS "OpenImageIO oiiiotool = ${OIIOTOOL_BIN}" )
endif ()
include (FindPackageHandleStandardArgs)
+76
View File
@@ -0,0 +1,76 @@
###########################################################################
# CMake module to find OptiX
#
# This module will set
# OPTIX_FOUND True, if OptiX is found
# OPTIX_INCLUDE_DIR directory where OptiX headers are found
# OPTIX_LIBRARIES libraries for OptiX
#
# Special inputs:
# OPTIXHOME - custom "prefix" location of OptiX installation
# (expecting bin, lib, include subdirectories)
# If 'OPTIXHOME' not set, use the env variable of that name if available
if (NOT OPTIXHOME)
if (NOT $ENV{OPTIXHOME} STREQUAL "")
set (OPTIXHOME $ENV{OPTIXHOME})
elseif (NOT $ENV{OPTIX_INSTALL_DIR} STREQUAL "")
set (OPTIXHOME $ENV{OPTIX_INSTALL_DIR})
endif ()
endif ()
if (NOT OptiX_FIND_QUIETLY)
message (STATUS "OPTIXHOME = ${OPTIXHOME}")
endif ()
find_path (OPTIX_INCLUDE_DIR
NAMES optix.h
HINTS ${OPTIXHOME}/include
PATH_SUFFIXES include )
# Macro adapted from https://github.com/nvpro-samples/optix_advanced_samples
macro(OPTIX_find_api_library name version)
find_library(${name}_LIBRARY
NAMES ${name}.${version} ${name}
PATHS "${OPTIXHOME}/lib64"
NO_DEFAULT_PATH
)
find_library(${name}_LIBRARY
NAMES ${name}.${version} ${name}
)
endmacro()
OPTIX_find_api_library(optix 1)
OPTIX_find_api_library(optixu 1)
OPTIX_find_api_library(optix_prime 1)
set (OPTIX_LIBRARIES ${optix_LIBRARY} ${optixu_LIBRARY} ${optix_prime_LIBRARY})
# Pull out the API version from optix.h
file(STRINGS ${OPTIX_INCLUDE_DIR}/optix.h OPTIX_VERSION_LINE LIMIT_COUNT 1 REGEX OPTIX_VERSION)
string(REGEX MATCH "([0-9]+)" OPTIX_VERSION_STRING "${OPTIX_VERSION_LINE}")
math(EXPR OPTIX_VERSION_MAJOR "${OPTIX_VERSION_STRING}/10000")
math(EXPR OPTIX_VERSION_MINOR "(${OPTIX_VERSION_STRING}%10000)/100")
math(EXPR OPTIX_VERSION_MICRO "${OPTIX_VERSION_STRING}%100")
set(OPTIX_VERSION "${OPTIX_VERSION_MAJOR}.${OPTIX_VERSION_MINOR}.${OPTIX_VERSION_MICRO}")
message (STATUS "OptiX version = ${OPTIX_VERSION}")
if (NOT OptiX_FIND_QUIETLY)
message (STATUS "OptiX includes = ${OPTIX_INCLUDE_DIR}")
message (STATUS "OptiX libraries = ${OPTIX_LIBRARIES}")
endif ()
mark_as_advanced (
OPTIX_INCLUDE_DIR
OPTIX_LIBRARIES
OPTIX_VERSION
)
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (OptiX
FOUND_VAR OPTIX_FOUND
REQUIRED_VARS OPTIX_INCLUDE_DIR OPTIX_LIBRARIES OPTIX_VERSION
VERSION_VAR OPTIX_VERSION
)
+11
View File
@@ -6,6 +6,8 @@
# PUGIXML_LIBRARIES - library to link against
# PUGIXML_FOUND - true if pugixml was found.
unset (PUGIXML_LIBRARY CACHE)
unset (PUGIXML_INCLUDE_DIR CACHE)
find_path (PUGIXML_INCLUDE_DIR
NAMES pugixml.hpp
PATHS ${PUGIXML_HOME}/include
@@ -17,6 +19,15 @@ find_library (PUGIXML_LIBRARY
/usr/local/lib
/usr/local/lib/pugixml-1.8)
# Second chance -- if not found, look in the OIIO distro
if (NOT PUGIXML_INCLUDE_DIR AND OPENIMAGEIO_INCLUDE_DIR)
find_path (PUGIXML_INCLUDE_DIR
NAMES pugixml.hpp
PATHS ${OPENIMAGEIO_INCLUDE_DIR}/OpenImageIO)
set (PUGIXML_LIBRARY ${OPENIMAGEIO_LIBRARIES})
endif ()
# Support the REQUIRED and QUIET arguments, and set PUGIXML_FOUND if found.
include (FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS (PugiXML DEFAULT_MSG PUGIXML_LIBRARY
+64
View File
@@ -1,6 +1,8 @@
set (public_docs osl-languagespec.pdf
testshade.md.html
osltoy.md.html
markdeep.min.js
docs.css
)
install (FILES ${public_docs} DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT documentation)
@@ -15,3 +17,65 @@ install ( FILES "${PROJECT_SOURCE_DIR}/LICENSE"
file (GLOB testshade_figures "Figures/testshade/*.jpg")
install (FILES ${testshade_figures}
DESTINATION ${CMAKE_INSTALL_DOCDIR}/Figures/testshade )
file (GLOB osltoy_figures "Figures/osltoy/*.jpg")
install (FILES ${osltoy_figures}
DESTINATION ${CMAKE_INSTALL_DOCDIR}/Figures/osltoy )
# Macro to compile a shader with oslc. Syntax is:
# docdeep_generate (SOURCE osl_source_file
# [ NAME doc_name ]
# [ DOC_LIST list_to_append_doc_filename ] )
# [ SRC_LIST list_to_append_src_filename ] )
macro (docdeep_generate)
cmake_parse_arguments (_docdeep "" "NAME;DOC_LIST;SRC_LIST" "SOURCE" ${ARGN})
# ^^ syntax: prefix options one-arg-keywords multi-arg-keywords args
set (oslfile ${_docdeep_SOURCE})
set (mdfile "${_docdeep_NAME}.md.html")
if (VERBOSE)
message (STATUS "docdeep will make '${mdfile}'")
endif ()
set (docdeep_program ${CMAKE_SOURCE_DIR}/src/build-scripts/docdeep.py)
add_custom_command (OUTPUT ${mdfile}
COMMAND python ${docdeep_program} -d ${_docdeep_NAME} -s docs.css
${_docdeep_SOURCE} > "${CMAKE_CURRENT_BINARY_DIR}/${mdfile}"
MAIN_DEPENDENCY ${docdeep_program}
DEPENDS ${_docdeep_SOURCE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "docdeep ${_docdeep_NAME}"
)
if (_docdeep_DOC_LIST)
list (APPEND ${_docdeep_DOC_LIST} "${CMAKE_CURRENT_BINARY_DIR}/${mdfile}")
endif ()
if (_docdeep_SRC_LIST)
list (APPEND ${_docdeep_SRC_LIST} ${_docdeep_SOURCE})
endif ()
endmacro ()
set (all_docdeep_docs "")
set (all_docdeep_srcs "")
docdeep_generate (NAME OSLQuery
SOURCE ${PROJECT_SOURCE_DIR}/src/include/OSL/oslquery.h
${PROJECT_SOURCE_DIR}/src/oslinfo/oslinfo.cpp
DOC_LIST all_docdeep_docs
SRC_LIST all_docdeep_srcs)
docdeep_generate (NAME docdeep
SOURCE ${PROJECT_SOURCE_DIR}/src/build-scripts/docdeep.py
DOC_LIST all_docdeep_docs
SRC_LIST all_docdeep_srcs)
add_custom_target (generated_docs ALL
DEPENDS ${all_docdeep_docs} ${all_docdeep_srcs}
SOURCES ${all_docdeep_srcs}
)
message (STATUS "All docdeep docs = ${all_docdeep_docs}")
install (FILES ${all_docdeep_docs}
DESTINATION ${CMAKE_INSTALL_DOCDIR}
COMPONENT documentation
)
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

+9 -3
View File
@@ -6,7 +6,7 @@ all: languagespec.pdf
# document making rule: use pdflatex
languagespec.pdf: *.tex languagespec.aux macros.aux Figures/*.pdf Figures/*png
languagespec.pdf: *.tex Figures/*.pdf Figures/*png
pdflatex ${PDFLATEX_FLAGS} languagespec.tex
@@ -15,8 +15,14 @@ languagespec.pdf: *.tex languagespec.aux macros.aux Figures/*.pdf Figures/*png
index: languagespec_index
languagespec_index:
pdflatex ${PDFLATEX_FLAGS} languagespec.tex
pdflatex ${PDFLATEX_FLAGS} languagespec.tex
makeindex languagespec
pdflatex ${PDFLATEX_FLAGS} languagespec.tex
pdflatex ${PDFLATEX_FLAGS} languagespec.tex languagespec.aux macros.aux
pdflatex ${PDFLATEX_FLAGS} languagespec.tex languagespec.aux macros.aux languagespec.toc
clean:
rm -f languagespec.aux languagespec.idx languagespec.ilg languagespec.ind languagespec.log
rm -f languagespec.out languagespec.pdf languagespec.toc macros.aux
.PHONY: clean
+165
View File
@@ -0,0 +1,165 @@
/* Custom stylesheet.
* Bits copied from many sources, including those that come with Markdeep.
*/
/* Custom stylesheet for API documentation by Aras Pranckevičius, http://aras-p.info/
and tweaked by Morgan McGuire.
Licensed as public domain or BSD 2-clause, whichever is more convenient for you.
Originally from https://github.com/aras-p/markdeep-docs-style */
/* Some modifications by Larry Gritz */
body {
max-width: 50em;
/* font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; */
text-align: left;
margin: 1.5em;
padding: 0 1em;
}
/* if screen is wide enough, put table of contents on the right side */
@media screen and (min-width: 64em) {
.md .longTOC, .md .mediumTOC, .md .shortTOC {
position: fixed;
max-width: 20em;
left: 54em;
display:block;
}
}
/* for narrow screens or print, hide table of contents */
@media screen and (max-width: 64em) {
.md .longTOC, .md .mediumTOC, .md .shortTOC { display: none; }
}
@media print {
.md .longTOC, .md .mediumTOC, .md .shortTOC { display: none; }
body { max-width: 100%; }
}
/* reset heading/link fonts to that of body */
.md a,
.md div.title, contents, .md .tocHeader,
.md h1, .md h2, .md h3, .md h4, .md h5, .md h6,
.md .nonumberh1, .md .nonumberh2, .md .nonumberh3, .md .nonumberh4, .md .nonumberh5, .md .nonumberh6,
.md .shortTOC, .md .mediumTOC, .md .longTOC {
font-family: inherit;
}
.md div.title {
/*orig margin: 0.4em 0 0 0; */
margin: 0.4em 0 2em 0; /* LG */
padding: 0;
/*orig text-align: inherit; */
text-align: center; /* LG */
text-decoration: underline; /* LG */
}
.md div.subtitle {
/* orig text-align: inherit; */
text-align: center; /* LG */
}
/* faint border below headings */
.md h1, .md h2, .md h3, .md h4,
.md .nonumberh1, .md .nonumberh2, .md .nonumberh3, .md .nonumberh4 {
border-bottom: 1px solid rgba(0,0,0,.1);
}
/* heading font styles */
.md h1, .md .nonumberh1, .md div.title {
font-size: 150%;
font-weight: 600;
color: rgba(0,0,0,.7);
}
.md h2, .md .nonumberh2 {
font-size: 120%;
font-weight: 400;
color: rgba(0,0,0,.9);
}
.md h3, .md .nonumberh3 {
font-size: 110%;
font-weight: 400;
color: rgba(0,0,0,.7);
}
/* no numbering of headings */
/*.md h1:before, .md h2:before, .md h3:before, .md h4:before { content: none; }*/
/* link styling */
.md a:link, .md a:visited {
color: #3f51b5;
}
/* inline and block code */
.md code, .md pre.listing {
background-color: rgba(0,0,0,.03);
padding: 0.1em 0.2em;
border-radius: 0.15em;
}
.md pre.listing code {
background-color: transparent;
padding: 0;
border: none;
}
/* table of contents styling; make all 3 forms of it look the same */
.md .longTOC, .md .mediumTOC, .md .shortTOC {
font-size: inherit;
line-height: 120%;
margin: 1em 0;
padding: .4rem;
border-left: .1rem solid #3f51b5;
}
.md .tocHeader {
margin: 0;
padding: 0;
border: none;
font-size: inherit;
}
.md .tocNumber {
display: none;
}
.md .longTOC .level1, .md .mediumTOC .level1, .md .shortTOC .level1 {
font-weight: inherit;
padding: 0;
margin: 0;
}
.md .longTOC p, .md .mediumTOC p, .md .shortTOC p {
overflow: hidden;
text-overflow: ellipsis;
}
.md .longTOC center, .md .mediumTOC center, .md .shortTOC center {
text-align: left;
}
.md .longTOC b, .md .mediumTOC b, .md .shortTOC b {
font-weight: 400;
}
.md .longTOC a, .md .mediumTOC a, .md .shortTOC a {
color: black;
}
.md .longTOC .level1, .md .mediumTOC .level1, .md .shortTOC .level1,
.md .longTOC .level2, .md .mediumTOC .level2, .md .shortTOC .level2,
.md .longTOC .level3, .md .mediumTOC .level3, .md .shortTOC .level3 {
white-space: nowrap;
margin: 0;
padding: 0;
font-size: 90%;
}
/* tables; use fainter colors than regular markdeep style */
.md table.table {
font-size: 90%;
}
.md table.table th {
border: none;
background-color: #ccc;
color: rgba(0,0,0,.6);
}
.md table.table tr, .md table.table td {
border-color: #eee;
}
.md table.table tr:nth-child(even) {
background-color: #f4f4f4;
}
+60 -37
View File
@@ -43,7 +43,7 @@
\def\langname{Open Shading Language\xspace}
\def\product{{\sffamily Open Shading Language}\xspace}
\def\versionnumber{1.9}
\def\versionnumber{1.10}
\def\productver{\product\ {\sffamily \versionnumber}\xspace}
@@ -52,17 +52,16 @@
%\textregistered\
{\bf\sffamily \versionnumber} \medskip \\ \huge
Language Specification
%\\ \large (CONFIDENTIAL --- draft in progress)
} \bigskip }
\author{
\copyright\ Copyright 2009-2017 Sony Pictures Imageworks Inc., et al. All rights reserved.
\copyright\ Copyright 2009-2018 Sony Pictures Imageworks Inc., et al. All rights reserved.
\bigskip \\
\vspace{1in} \\
Editor: Larry Gritz \\
\emph{lg@imageworks.com}
}
\date{{\large Date: 30 Jun 2017 \\
% (with corrections, 12 May 2017)
\date{{\large Date: 31 Mar 2018 \\
(with corrections, 12 Apr 2019)
}
\bigskip
\bigskip
@@ -539,6 +538,8 @@ source code:
\item {\cf source} is a {\cf float} or {\cf int} and {\cf dest} is a
\emph{triple} (the scalar value will be replicated for all three components
of the triple).
\item {\cf source} is a single component of an aggregate type (e.g. one
channel of a {\cf color}) and {\cf dest} is a {\cf float} (or vice versa).
\end{itemize}
\subsection*{Geometric primitives}
@@ -586,13 +587,6 @@ point-by-point basis, and volume shaders that describe how light is
scattered within a region of space. A particular renderer may have
additional shader types that it supports.
%\subsection*{Shader types}
%
%There are several types of shaders: surface, displacement, light,
%volume. The type of shader determines what it's allowed to do (for
%example, only displacement shaders can alter the surface position).
%There is also a generic kind of shader that can be used for any of the
%shader uses.
\subsection*{Shader execution state: parameter binding and global variables}
@@ -614,7 +608,7 @@ information about the renderer as a whole (rendering options, etc.).
Surface shaders (and volume shaders) do not by themselves compute the
final color of light emanating from the surface (or along a volume).
Rather, the compute a \emph{closure}, which is a symbolic representation
Rather, they compute a \emph{closure}, which is a symbolic representation
describing the appearance of the surface, that may be more fully
evaluated later. This is in effect a parameterized formula, in which
some inputs have definite numeric values, but others may depend on
@@ -979,7 +973,7 @@ different behaviors or appearances when used on different objects.
Shader parameters are specified in the shader declaration, in
parentheses after the shader's name. This is much like the parameters
to a \languagename function (or a function in C or similar languages),
to an OSL function (or a function in C or similar languages),
except that shader parameters must have an \emph{initializer}, giving a
default value for the parameter. Shader parameter default initializers
may be expressions (i.e., may be computed rather than restricted to
@@ -1865,7 +1859,7 @@ reference to a named space:
\end{code}
\noindent The first form creates the matrix that transforms points from
\commonspace to \shaderspace. Transforming points by this matrix
\shaderspace to \commonspace. Transforming points by this matrix
is identical to calling {\cf transform("shader",...)}.
The second form prepends the current-to-world transformation matrix
onto the $4 \times 4$ matrix with components $m_{0,0} ... m_{3,3}$.
@@ -2060,6 +2054,22 @@ you can construct built-in types like \color or \point:
RGBA d = add (c, RGBA(color(.3,.4,.5), 0));
\end{code}
\NEW % 1.10
You may also use the \emph{compound initializer list} syntax to construct a
type when it can be deduced from context which compound type is required.
For example, this is equivalent to the preceding example:
\begin{code}
RGBA c = {col,alpha}; // deduce by what is being assigned to
RGBA add (RGBA a, RGBA b)
{
return { a.rgb+b.rgb, a.a+b.a }; // deduce by func return type
}
RGBA d = add (c, {{.3,.4,.5}, 0}); // deduce by expected arg type
\end{code}
It is permitted to have a structure field that is an array, as well as to
have an array of structures. But it is not currently permitted to ``nest''
arrays (that is, to have an array of structs which contain members that are
@@ -2105,7 +2115,7 @@ At present, the only type of \closure supported by \langname is the
form a linear combination of \colorclosure's. Additional closure types
and operations are reserved for future use.
Allowable operations on \colorclosure's include:
Allowable operations on \colorclosure include:
\medskip
\noindent \begin{tabular}{|p{2.25in}|p{1.25in}|p{1.75in}|}
@@ -2653,8 +2663,13 @@ that point, and designates the value that will be returned (if not a
Functions may be \emph{overloaded}. That is, multiple functions may be
defined to have the same name, as long as they have differently-typed
parameters, so that when the function is called the list of arguments
can disambiguate which version of the function is desired.
parameters, so that when the function is called the list of arguments can
select which version of the function is desired. When there are multiple
potential matches, function versions whose argument types match exactly are
favored, followed by those that match with type coercion (for example,
passing an {\cf int} when the function expects a {\cf float}, or passing a
{\cf float} when the function expects a \color), and finally by trying to
match the return value to the type of variable the result is assigned to.
\subsection{Operator overloading}
\label{sec:syntax:operatoroverloading}
@@ -3067,16 +3082,6 @@ The {\cf mix} function returns a linear blending :
$ x*(1-\alpha) + y*(\alpha) $
\apiend
\apiitem{int {\ce isnan} (float x) \\
int {\ce isinf} (float x) \\
int {\ce isfinite} (float x)}
\indexapi{isnan()} \indexapi{isinf()} \indexapi{isfinite()}
The {\cf isnan()} function returns 1 if $x$ is a not-a-number (NaN)
value, 0 otherwise. The {\cf isinf()} function returns 1 if $x$ is an
infinite (Inf or --Inf) value, 0 otherwise. The {\cf isfinite()}
function returns 1 if $x$ is an ordinary number (neither infinite nor
NaN), 0 otherwise. \apiend
\apiitem{\emph{type} {\ce select} (\emph{type} x, \emph{type} y, \emph{type} cond) \\
\emph{type} {\ce select} (\emph{type} x, \emph{type} y, float cond) \\
\emph{type} {\ce select} (\emph{type} x, \emph{type} y, int cond)}
@@ -3242,10 +3247,12 @@ and {\cf eta} is the ratio of refractive index of the medium
containing {\cf I} to that on the opposite side of the surface.
\apiend
\apiitem{point {\ce rotate} (point Q, float angle, point P0, point P1)}
\apiitem{point {\ce rotate} (point Q, float angle, point P0, point P1) \\
point {\ce rotate} (point Q, float angle, vector axis)}
\indexapi{rotate()}
Returns the point computed by rotating point {\cf Q} by {\cf angle}
radians about the axis that passes from point {\cf P0} to {\cf P1}.
Returns the point computed by rotating point {\cf Q} by {\cf angle}
radians about the axis that passes from point {\cf P0} to {\cf P1},
or about the {\cf axis} vector centered on the origin.
\apiend
\apiitem{\emph{ptype} {\ce transform} (string tospace, \emph{ptype} p) \\
@@ -3441,11 +3448,15 @@ The \emph{type} may be any of of \float, \color, \point, \vector, or
performed component-by-component (separately for $x$, $y$, and $z$).
\apiend
\apiitem{float {\ce linearstep} (float edge0, float edge1, float x)}
\apiitem{float {\ce linearstep} (float edge0, float edge1, float x) \\
\emph{type} {\ce linearstep} (\emph{type} edge0, \emph{type} edge1, \emph{type} x)}
\indexapi{linearstep()}
Returns 0 if $x \le {\mathit edge0}$, and 1 if $x \ge {\mathit edge1}$,
and performs a linear
interpolation between 0 and 1 when ${\mathit edge0} < x < {\mathit edge1}$.
This is equivalent to {\cf step(edge0, x)} when {\cf edge0 == edge1}.
For \color and \point-like types, the computations are
performed component-by-component (separately for $x$, $y$, and $z$).
\apiend
\apiitem{float {\ce smoothstep} (float edge0, float edge1, float x) \\
@@ -3459,10 +3470,11 @@ with a smooth transition.
The \emph{type} may be any of of \float, \color, \point, \vector, or
\normal. For \color and \point-like types, the computations are
performed component-by-component (separately for $x$, $y$, and $z$).
performed component-by-component.
\apiend
\apiitem{float {\ce smooth_linearstep} (float edge0, float edge1, float x, float eps)}
\apiitem{float {\ce smooth_linearstep} (float edge0, float edge1, float x, float eps) \\
\emph{type} {\ce smooth_linearstep} (\emph{type} edge0, \emph{type} edge1, \emph{type} x, \emph{type} eps)}
\indexapi{smooth_linearstep()}
This function is strictly linear between ${\mathit edge0}+{\mathit eps}$ and ${\mathit edge1}-{\mathit eps}$
but smoothly ramps to 0 between ${\mathit edge0}-{\mathit eps}$ and ${\mathit edge0}+{\mathit eps}$
@@ -3470,6 +3482,8 @@ and smoothly ramps to 1 between ${\mathit edge1}-{\mathit eps}$ and ${\mathit ed
It is 0 when $x \le {\mathit edge0}-{\mathit eps}$, and 1 if $x \ge {\mathit edge1}+{\mathit eps}$,
and performs a linear
interpolation between 0 and 1 when ${\mathit edge0} < x < {\mathit edge1}$.
For \color and \point-like types, the computations are
performed component-by-component.
\apiend
@@ -3688,7 +3702,7 @@ animation (provided its input is \emph{precisely} identical).
int {\ce hash} (float u, float v) \\
int {\ce hash} (point p) \\
int {\ce hash} (point p, float t) \\
int {\ce hash) (int i)}}
int {\ce hash} (int i)}
\indexapi{hash()}
\NEW % 1.9
Returns a deterministic, repeatable integer \emph{hash} of the 1-, 2-, 3-,
@@ -4031,7 +4045,7 @@ Identical to {\cf regex_search}, except that it must match the
Perform a texture lookup of an image file, indexed by 2D coordinates
$(s,t)$, antialiased over a region defined by the differentials
\emph{dsdx, dtdx, dsty} and \emph{dtdy} (which are computed
\emph{dsdx, dtdx, dsdy} and \emph{dtdy} (which are computed
automatically from $s$ and $t$, if not supplied). Whether the results
are assigned to a \float or a \color (or type cast to one of those)
determines whether the texture lookup is a single channel or three
@@ -4204,6 +4218,14 @@ The first channel to look up from the texture map (default: 0).
\apiend
\vspace{-16pt}
\apiitem{"subimage", <int> \\
"subimage", <string>}
\vspace{12pt}
Specify the subimage (by numerical index, or name) of the subimage
within a multi-image texture file (default: subimage 0).
\apiend
\vspace{-16pt}
\apiitem{"fill", <float>}
\vspace{12pt}
The value to return for any channels that are requested,
@@ -4922,7 +4944,7 @@ wish to make queryable.
\apiend
\begin{table}[htbp]
\caption{Names of standard attributes that may be retrieved.}\label{tab:cameraattributes}
\caption{Names of standard attributes that may be retrieved.}\label{tab:stdattributes}
\begin{tabular}{|p{1.8in}|p{0.6in}|p{2.8in}|}
\hline
{\bf Name} & {\bf Type} & {\bf Description} \\
@@ -5435,6 +5457,7 @@ nothing (empty, no token).
\alt <ternary-expression>
\alt <typecast-expression>
\alt <variable-ref>
\alt <compound-initializer>
<compound-expression> ::= <expression> \{ "," <expression> \}
+6 -5
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
+243
View File
@@ -0,0 +1,243 @@
**osltoy**
revision date: 30 Nov 2017
_osltoy_ basics
==================================================
`osltoy` is an interactive editor and realtime visualizer for OSL shaders.
It is inspired by [Shadertoy](https://www.shadertoy.com/) by Inigo Quilez.
But it uses a real VFX shading language!
![osltoy](Figures/osltoy/osltoy-fbm.jpg width="400px")
The basic functionaity of `osltoy` is:
* Allow you to edit OSL shader source code.
* Live and continuous rendering of an "image" that is the result of running
your shader on each pixel of the image (pixel color is taken from the
shader's parameter `output color Cout`.)
## Command line
Launch `osltoy` from the command line:
`osltoy` [*options*]
Additional command line arguments:
`--help`
: Print command line options and other help.
`-v`
: Verbose mode. (Doesn't really do anything currently.)
`--res` *xres* *yres* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
: Specifies the resolution of the render window (default: 512 x 512).
`--threads` *n*
: Specifies the number of simultaneous threads to use for shading. If not
specified, it will use all your hardware cores.
*filename.osl*
: If one or more filenames of shader source code are specified, they will
be loaded into editor tabs upon startup.
## osltoy Basics
First, let's launch `osltoy`:
```
$ osltoy
```
![ ](Figures/osltoy/osltoy-start.jpg width="400px")
This will start up a new `osltoy` session.
On the right half of the GUI is a code editor window. Below the code editor
is an area that will show you any compilation errors. The left half of the
GUI will display the results of the shader (a checkerboard if no shader
has been compiled yet). Below that is an area that will hold widgets to
allow adjustment of shader parameter values.
At the very bottom of the app window is a status bar showing time, frames
per second, and other status messages. At the very top of the app window
(or, on MacOS, at the top of the screen) is a menu bar with the usual set of
common operations.
### Loading and saving shaders
You can load a shader one of three ways:
1. Specify the filename of an existing shader when you launch the app:
```
osltoy test.osl
```
2. From a blank window, load an existing shader by selecting the menu
bar choice `File` --> `Open`, or hitting the hotkey `Ctrl-O` (on MacOS,
⌘`-O`). This will present a file selection dialog.
3. Just start typing in the editor window.
You can save the edited shader with the menu bar `File` --> `Save`
or the hotkey `Ctrl-S` (⌘`-S` on MacOS). If the file does not yet
have a name, you will be presented with a file save dialog (as you will
if you use `File` --> `Save As`).
!!! Note
Every time we talk about a `Ctrl-`*key* combination, if you are on MacOS
(OSX), that hotkey will be ⌘`-`*key*. This document won't awkwardly
repeat this clarification for every command.
### Compiling shaders
When you have loaded or edited your OSL source code, you can compile the
shader with menu `Tools` --> `Recompile shaders`, or by clicking the
`Recompile` button below the source code editor widget, or by using the
hotkey `Ctrl-R`.
!!! Warning
`osltoy` won't compile a buffer that doesn't have a filename ending in
`.osl`, and if you started with a blank window, it won't have a name at
all until you save the first time.
In the compilation status window below the editor, you will either see
an `Ok` message if the compiler succeeded, or the error output from the
compiler, as illustrated here:
![Compilation error display.](Figures/osltoy/osltoy-error.jpg width="512px")
!!! Warning
`osltoy` appears to let you load or create multiple shaders, appearing
in a tabbed editor. We'll get this working eventually (so you can edit
whole shader groups and all the shaders that are in them), but currently
only the shader in the first tab will be compiled and executed, so don't
get confused by the non-functional parts of the interface.
### Executing shaders and interactive changes
Once you compile the shader successfully, it will execute and display the
results of shading a rectangle.
![osltoy has executed the shader](Figures/osltoy/osltoy-fbm.jpg)
As soon as you recompile, the shader will be executed as quickly as possible
and displayed as an image on the left, with shader parameter adjustment
widgets below it.
Evey time you change a parameter value through its widget, the shader will
automatically recompile and re-execute. If you edit the text of the shader,
clicking the `Recompile` button or using the hotkey `Ctrl-R` will recompile
and re-execute the shader.
Rules of the game
==================
## Shader inputs and state
The shader is executed on every pixel of an image (defaulting to a 512x512
square, but you can change the resolution via a command line flag).
The `float u` and `v` global variables vary from 0 to 1 along the rectangle.
The `point P` global variable will be set to `(x,y,0)`, where `x` is the pixel
horizontal coordinate (0 to xres-1 as it goes from left to right) and `y`
is the pixel vertical coordinate (0 to yres-1 as it goes from top to bottom
of the image).
The `float time` global variable contains the time (in seconds) since the
last time the shader was recompiled. Making your shader change its behavior
based on the `time` variable will make an animated shader.
## Shader outputs
The color displayed is taken from the shader output parameter that is
declared like this:
```
output color Cout = 0
```
Whatever you place in that output will be the color displayed at each pixel
of the output image.
!!! Note
Your shader does not need to set `Ci` or deal with closures. The
`osltoy` app is just for exploring pattern generation, not illumination.
It doesn't actually have any notion of 3D geometry or lights.
## Shader execution
If your shader does not reference the `time` variable in any way, it will
only be executed once each time it recompiles. But if `time` appears in your
shader, it will execute repeatedly, as quickly as possible, until you exit
or recompile.
Shader execution will by default use enough threads to keep all your cores
busy. The command line option `--threads` can be used to limit the number
of cores (or to "over-thread").
Caveats, limitations, and broken stuff
========================
These are current limitations or breakages that we will fix over time.
* The GUI seems to let you open multiple editor tabs, but currently, the
only one that will compile and execute is the *first* (farthest to the left
tab that was loaded or saved under a name that ends in `".osl"`.
* We intend to add "Pause" and "Reset" buttons to control time.
* I tried to make the parameter adjustment widgets be clever about how
quickly to modify the values, depending on their range. But I don't have
it quite right. It's still being refined.
* There isn't yet have a way to get the shader itself to get information about
external events such as mouse clicks or key presses, but that would be
fun.
* There isn't yet a way for the shader to have *state* that can be computed,
stored, then re-read when the shader executes on the next frame.
Things to try
=============
* Try this:
` osltoy ` *osl_install_directory*`/shaders/mandelbrot.osl`
* Use the global `time` variable to make animated patterns.
* Explore noise functions and other pattern generation interactively.
* Explore (by keeping an eye on the "FPS" reading at the bottom) what shader
operations are fast and what is slow.
* Don't forget that `texture()` calls work as expected in shadertoy!
* `osltoy` is a great tool for leaning or *teaching* OSL.
* The actual "geometry" is just a rectangle, but like with Shadertoy,
you can make patterns that *look like* by implementing a simple ray tracer
in the shader itself, or using other clever tricks.
* Look at the many examples on [Shadertoy](https://www.shadertoy.com/)
for inspiration!
* Make crazy stuff and post the shaders to the `osl-dev` mail list!
<!-- Markdeep: --><style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style><script src="markdeep.min.js"></script><script src="https://casual-effects.com/markdeep/latest/markdeep.min.js?"></script><script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>
<link rel="stylesheet" href="docs.css?">
+1 -3
View File
@@ -1003,7 +1003,5 @@ tests, you can:
<!-- Markdeep: --><style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style><script src="markdeep.min.js"></script><script src="https://casual-effects.com/markdeep/latest/markdeep.min.js?"></script><script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>
<link rel="stylesheet" href="docs.css?">
<style>
h1, .nonumberh1 { page-break-before: always }
</style>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+94
View File
@@ -0,0 +1,94 @@
/*
Copyright (c) 2009-2018 Sony Pictures Imageworks Inc., et al.
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Sony Pictures Imageworks nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <OSL/oslconfig.h>
// USAGE NOTES:
//
// To define a "standard" DeviceString, add a STRDECL to <OSL/strdecls.h>
// specifying the string literal and the name to use for the variable.
OSL_NAMESPACE_ENTER
// Strings are stored in a block of CUDA device memory. String variables hold a
// pointer to the start of the char array for each string. Each canonical string
// has a unique entry in the table, so two strings can be tested for equality by
// comparing their addresses.
//
// As a convenience, the ustring hash and the length of the string are also
// stored in the table, in the 16 bytes preceding the characters.
struct DeviceString {
const char* m_chars;
OSL_HOSTDEVICE uint64_t hash()
{
return *(uint64_t*)(m_chars - sizeof(uint64_t) - sizeof(uint64_t));
}
OSL_HOSTDEVICE uint64_t length()
{
return *(uint64_t*)(m_chars - sizeof(uint64_t));
}
OSL_HOSTDEVICE const char* c_str()
{
return m_chars;
}
OSL_HOSTDEVICE bool operator== (const DeviceString& other) const
{
return m_chars == other.m_chars;
}
OSL_HOSTDEVICE bool operator!= (const DeviceString& other) const
{
return m_chars != other.m_chars;
}
};
// Handy re-casting macro
#define DEVSTR(cstr) (*(OSL::DeviceString*)&cstr)
#ifdef __CUDA_ARCH__
namespace DeviceStrings {
#define STRDECL(str,var_name) \
extern __device__ DeviceString var_name;
#include <OSL/strdecls.h>
#undef STRDECL
}
#endif
OSL_NAMESPACE_EXIT
+118 -115
View File
@@ -29,8 +29,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <initializer_list>
#include <OSL/oslconfig.h>
#include <OSL/oslversion.h>
#include <OpenImageIO/fmath.h>
OSL_NAMESPACE_ENTER
@@ -61,109 +64,109 @@ public:
/// Default ctr leaves everything uninitialized
///
constexpr Dual () { }
OSL_HOSTDEVICE OIIO_CONSTEXPR14 Dual () { }
/// Construct a Dual from just a real value (derivs set to 0)
///
OIIO_CONSTEXPR14 Dual (const T &x) {
OSL_HOSTDEVICE OIIO_CONSTEXPR14 Dual (const T &x) {
m_data[0] = x;
for (int i = 1; i <= PARTIALS; ++i)
m_data[i] = T(0.0);
}
/// Copy constructor from another Dual of same type and dimension.
OIIO_CONSTEXPR14 Dual (const Dual &x) {
OSL_HOSTDEVICE OIIO_CONSTEXPR14 Dual (const Dual &x) {
for (int i = 0; i <= PARTIALS; ++i)
m_data[i] = T(x.m_data[i]);
}
#if 1
/// Copy constructor from another Dual of same dimension and different,
/// but castable, data type.
template<class F>
OIIO_CONSTEXPR14 Dual (const Dual<F,PARTIALS> &x) {
OSL_HOSTDEVICE OIIO_CONSTEXPR14 Dual (const Dual<F,PARTIALS> &x) {
for (int i = 0; i <= PARTIALS; ++i)
m_data[i] = T(x.elem(i));
}
#endif
/// Construct a Dual from a real and infinitesimals.
///
constexpr Dual (const T &x, const T &dx) : m_data{ x, dx } {
OSL_HOSTDEVICE constexpr Dual (const T &x, const T &dx) : m_data{ x, dx } {
static_assert(PARTIALS==1, "Wrong number of initializers");
}
constexpr Dual (const T &x, const T &dx, const T &dy)
OSL_HOSTDEVICE constexpr Dual (const T &x, const T &dx, const T &dy)
: m_data{ x, dx, dy }
{
static_assert(PARTIALS==2, "Wrong number of initializers");
}
void set (const T &x, const T &dx) {
OSL_HOSTDEVICE void set (const T &x, const T &dx) {
static_assert(PARTIALS==1, "Wrong number of initializers");
m_data[0] = x;
m_data[1] = dx;
}
void set (const T &x, const T &dx, const T &dy) {
OSL_HOSTDEVICE void set (const T &x, const T &dx, const T &dy) {
static_assert(PARTIALS==2, "Wrong number of initializers");
m_data[0] = x;
m_data[1] = dx;
m_data[2] = dy;
}
OIIO_CONSTEXPR14 Dual (std::initializer_list<T> vals) {
OSL_HOSTDEVICE OIIO_CONSTEXPR14 Dual (std::initializer_list<T> vals) {
#if OIIO_CPLUSPLUS_VERSION >= 14
static_assert (vals.size() == elements, "Wrong number of initializers");
#endif
for (int i = 0; i < elements; ++i)
m_data[i] = vals.begin()[i];
}
/// Return the real value.
constexpr const T& val () const { return m_data[0]; }
T& val () { return m_data[0]; }
OSL_HOSTDEVICE constexpr const T& val () const { return m_data[0]; }
OSL_HOSTDEVICE T& val () { return m_data[0]; }
/// Return the partial derivative with respect to x.
constexpr const T& dx () const { return m_data[1]; }
T& dx () { return m_data[1]; }
OSL_HOSTDEVICE constexpr const T& dx () const { return m_data[1]; }
OSL_HOSTDEVICE T& dx () { return m_data[1]; }
/// Return the partial derivative with respect to y.
/// Only valid if there are at least 2 partial dimensions.
constexpr const T& dy () const {
OSL_HOSTDEVICE constexpr const T& dy () const {
static_assert(PARTIALS>=2, "Cannot call dy without at least 2 partials");
return m_data[2];
}
T& dy () {
OSL_HOSTDEVICE T& dy () {
static_assert(PARTIALS>=2, "Cannot call dy without at least 2 partials");
return m_data[2];
}
/// Return the partial derivative with respect to z.
/// Only valid if there are at least 3 partial dimensions.
constexpr const T& dz () const {
OSL_HOSTDEVICE constexpr const T& dz () const {
static_assert(PARTIALS>=3, "Cannot call dz without at least 3 partials");
return m_data[3];
}
T& dz () {
OSL_HOSTDEVICE T& dz () {
static_assert(PARTIALS>=3, "Cannot call dz without at least 3 partials");
return m_data[3];
}
/// Clear the derivatives; leave the value alone.
void clear_d () {
OSL_HOSTDEVICE void clear_d () {
for (int i = 1; i <= PARTIALS; ++i)
m_data[i] = T(0.0);
}
/// Return the i-th partial derivative.
constexpr const T& partial (int i) const {
OSL_HOSTDEVICE constexpr const T& partial (int i) const {
return m_data[i+1];
}
/// Return a mutable reference to the i-th partial derivative.
/// Use with caution!
T& partial (int i) {
OSL_HOSTDEVICE T& partial (int i) {
return m_data[i+1];
}
/// Assignment of a real (the derivs are implicitly 0).
const Dual & operator= (const T &x) {
OSL_HOSTDEVICE const Dual & operator= (const T &x) {
m_data[0] = x;
for (int i = 1; i <= PARTIALS; ++i)
m_data[i] = T(0);
@@ -172,8 +175,8 @@ public:
/// Access like an array -- be careful! Element 0 is the main value,
/// elements [1..PARTIALS] are the infinitessimals.
constexpr const T& elem (int i) const { return m_data[i]; }
T& elem (int i) { return m_data[i]; }
OSL_HOSTDEVICE constexpr const T& elem (int i) const { return m_data[i]; }
OSL_HOSTDEVICE T& elem (int i) { return m_data[i]; }
/// Stream output. Format as: "val[dx,dy,...]"
///
@@ -217,7 +220,7 @@ template<class T> using Dual2 = Dual<T,2>;
/// Addition of duals.
///
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P> operator+ (const Dual<T,P> &a, const Dual<T,P> &b)
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P> operator+ (const Dual<T,P> &a, const Dual<T,P> &b)
{
Dual<T,P> result = a;
for (int i = 0; i <= P; ++i)
@@ -227,7 +230,7 @@ inline OIIO_CONSTEXPR14 Dual<T,P> operator+ (const Dual<T,P> &a, const Dual<T,P>
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P> operator+ (const Dual<T,P> &a, const T &b)
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P> operator+ (const Dual<T,P> &a, const T &b)
{
Dual<T,P> result = a;
result.val() += b;
@@ -236,7 +239,7 @@ inline OIIO_CONSTEXPR14 Dual<T,P> operator+ (const Dual<T,P> &a, const T &b)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P> operator+ (const T &a, const Dual<T,P> &b)
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P> operator+ (const T &a, const Dual<T,P> &b)
{
Dual<T,P> result = b;
result.val() += a;
@@ -245,7 +248,7 @@ inline OIIO_CONSTEXPR14 Dual<T,P> operator+ (const T &a, const Dual<T,P> &b)
template<class T, int P>
inline Dual<T,P>& operator+= (Dual<T,P> &a, const Dual<T,P> &b)
OSL_HOSTDEVICE inline Dual<T,P>& operator+= (Dual<T,P> &a, const Dual<T,P> &b)
{
for (int i = 0; i <= P; ++i)
a.elem(i) += b.elem(i);
@@ -254,7 +257,7 @@ inline Dual<T,P>& operator+= (Dual<T,P> &a, const Dual<T,P> &b)
template<class T, int P>
inline Dual<T,P>& operator+= (Dual<T,P> &a, const T &b)
OSL_HOSTDEVICE inline Dual<T,P>& operator+= (Dual<T,P> &a, const T &b)
{
a.val() += b;
return a;
@@ -264,7 +267,7 @@ inline Dual<T,P>& operator+= (Dual<T,P> &a, const T &b)
/// Subtraction of duals.
///
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const Dual<T,P> &a, const Dual<T,P> &b)
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const Dual<T,P> &a, const Dual<T,P> &b)
{
Dual<T,P> result;
for (int i = 0; i <= P; ++i)
@@ -274,7 +277,7 @@ inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const Dual<T,P> &a, const Dual<T,P>
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const Dual<T,P> &a, const T &b)
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const Dual<T,P> &a, const T &b)
{
Dual<T,P> result = a;
result.val() -= b;
@@ -283,7 +286,7 @@ inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const Dual<T,P> &a, const T &b)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const T &a, const Dual<T,P> &b)
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const T &a, const Dual<T,P> &b)
{
Dual<T,P> result;
result.val() = a - b.val();
@@ -294,7 +297,7 @@ inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const T &a, const Dual<T,P> &b)
template<class T, int P>
inline Dual<T,P>& operator-= (Dual<T,P> &a, const Dual<T,P> &b)
OSL_HOSTDEVICE inline Dual<T,P>& operator-= (Dual<T,P> &a, const Dual<T,P> &b)
{
for (int i = 0; i <= P; ++i)
a.elem(i) -= b.elem(i);
@@ -303,7 +306,7 @@ inline Dual<T,P>& operator-= (Dual<T,P> &a, const Dual<T,P> &b)
template<class T, int P>
inline Dual<T,P>& operator-= (Dual<T,P> &a, const T &b)
OSL_HOSTDEVICE inline Dual<T,P>& operator-= (Dual<T,P> &a, const T &b)
{
a.val() -= b.val();
return a;
@@ -314,7 +317,7 @@ inline Dual<T,P>& operator-= (Dual<T,P> &a, const T &b)
/// Negation of duals.
///
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const Dual<T,P> &a)
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const Dual<T,P> &a)
{
Dual<T,P> result;
for (int i = 0; i <= P; ++i)
@@ -326,7 +329,7 @@ inline OIIO_CONSTEXPR14 Dual<T,P> operator- (const Dual<T,P> &a)
/// Multiplication of duals. This will work for any Dual<T>*Dual<S>
/// where T*S is meaningful.
template<class T, int P, class S>
inline OIIO_CONSTEXPR14 auto
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 auto
operator* (const Dual<T,P> &a, const Dual<S,P> &b) -> Dual<decltype(a.elem(0)*b.elem(0)),P>
{
// Use the chain rule
@@ -342,7 +345,7 @@ operator* (const Dual<T,P> &a, const Dual<S,P> &b) -> Dual<decltype(a.elem(0)*b.
/// Dual<T> * S where T*S is meaningful.
template<class T, int P, class S,
DUAL_REQUIRES(is_Dual<S>::value == false)>
inline OIIO_CONSTEXPR14 auto
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 auto
operator* (const Dual<T,P> &a, const S &b) -> Dual<decltype(a.elem(0)*b),P>
{
Dual<decltype(a.elem(0)*b),P> result;
@@ -356,7 +359,7 @@ operator* (const Dual<T,P> &a, const S &b) -> Dual<decltype(a.elem(0)*b),P>
///
template<class T, int P, class S,
DUAL_REQUIRES(is_Dual<S>::value == false)>
inline const Dual<T,P>& operator*= (Dual<T,P> &a, const S &b)
OSL_HOSTDEVICE inline const Dual<T,P>& operator*= (Dual<T,P> &a, const S &b)
{
for (int i = 0; i <= P; ++i)
a.elem(i) *= b;
@@ -369,7 +372,7 @@ inline const Dual<T,P>& operator*= (Dual<T,P> &a, const S &b)
/// Dual<T> * S where T*S is meaningful.
template<class T, int P, class S,
DUAL_REQUIRES(is_Dual<S>::value == false)>
inline OIIO_CONSTEXPR14 auto
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 auto
operator* (const S &b, const Dual<T,P> &a) -> Dual<decltype(a.elem(0)*b),P>
{
return a*b;
@@ -380,7 +383,7 @@ operator* (const S &b, const Dual<T,P> &a) -> Dual<decltype(a.elem(0)*b),P>
/// Division of duals.
///
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P> operator/ (const Dual<T,P> &a, const Dual<T,P> &b)
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P> operator/ (const Dual<T,P> &a, const Dual<T,P> &b)
{
T bvalinv = 1.0f / b.val();
T aval_bval = a.val() * bvalinv;
@@ -395,7 +398,7 @@ inline OIIO_CONSTEXPR14 Dual<T,P> operator/ (const Dual<T,P> &a, const Dual<T,P>
/// Division of dual by scalar.
///
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P> operator/ (const Dual<T,P> &a, const T &b)
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P> operator/ (const Dual<T,P> &a, const T &b)
{
T binv = 1.0f / b;
return a * binv;
@@ -405,7 +408,7 @@ inline OIIO_CONSTEXPR14 Dual<T,P> operator/ (const Dual<T,P> &a, const T &b)
/// Division of scalar by dual.
///
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P> operator/ (const T &aval, const Dual<T,P> &b)
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P> operator/ (const T &aval, const Dual<T,P> &b)
{
T bvalinv = 1.0f / b.val();
T aval_bval = aval * bvalinv;
@@ -420,75 +423,75 @@ inline OIIO_CONSTEXPR14 Dual<T,P> operator/ (const T &aval, const Dual<T,P> &b)
template<class T, int P>
inline constexpr bool operator< (const Dual<T,P> &a, const Dual<T,P> &b) {
OSL_HOSTDEVICE inline constexpr bool operator< (const Dual<T,P> &a, const Dual<T,P> &b) {
return a.val() < b.val();
}
template<class T, int P>
inline constexpr bool operator< (const Dual<T,P> &a, const T &b) {
OSL_HOSTDEVICE inline constexpr bool operator< (const Dual<T,P> &a, const T &b) {
return a.val() < b;
}
template<class T, int P>
inline constexpr bool operator> (const Dual<T,P> &a, const Dual<T,P> &b) {
OSL_HOSTDEVICE inline constexpr bool operator> (const Dual<T,P> &a, const Dual<T,P> &b) {
return a.val() > b.val();
}
template<class T, int P>
inline constexpr bool operator> (const Dual<T,P> &a, const T &b) {
OSL_HOSTDEVICE inline constexpr bool operator> (const Dual<T,P> &a, const T &b) {
return a.val() > b;
}
template<class T, int P>
inline constexpr bool operator<= (const Dual<T,P> &a, const Dual<T,P> &b) {
OSL_HOSTDEVICE inline constexpr bool operator<= (const Dual<T,P> &a, const Dual<T,P> &b) {
return a.val() <= b.val();
}
template<class T, int P>
inline constexpr bool operator<= (const Dual<T,P> &a, const T &b) {
OSL_HOSTDEVICE inline constexpr bool operator<= (const Dual<T,P> &a, const T &b) {
return a.val() <= b;
}
template<class T, int P>
inline constexpr bool operator>= (const Dual<T,P> &a, const Dual<T,P> &b) {
OSL_HOSTDEVICE inline constexpr bool operator>= (const Dual<T,P> &a, const Dual<T,P> &b) {
return a.val() >= b.val();
}
template<class T, int P>
inline constexpr bool operator>= (const Dual<T,P> &a, const T &b) {
OSL_HOSTDEVICE inline constexpr bool operator>= (const Dual<T,P> &a, const T &b) {
return a.val() >= b;
}
// Eliminate the derivatives of a number, works for scalar as well as Dual.
template<class T> inline constexpr const T&
template<class T> OSL_HOSTDEVICE inline constexpr const T&
removeDerivatives (const T &x) { return x; }
template<class T, int P> inline constexpr const T&
template<class T, int P> OSL_HOSTDEVICE inline constexpr const T&
removeDerivatives (const Dual<T,P> &x) { return x.val(); }
// Get the x derivative (or 0 for a non-Dual)
template<class T> inline constexpr const T&
template<class T> OSL_HOSTDEVICE inline constexpr const T&
getXDerivative (const T &x) { return T(0); }
template<class T, int P> inline constexpr const T&
template<class T, int P> OSL_HOSTDEVICE inline constexpr const T&
getXDerivative (const Dual<T,P> &x) { return x.partial(0); }
// Get the y derivative (or 0 for a non-Dual)
template<class T> inline constexpr const T&
template<class T> OSL_HOSTDEVICE inline constexpr const T&
getYDerivative (const T &x) { return T(0); }
template<class T, int P> inline constexpr const T&
template<class T, int P> OSL_HOSTDEVICE inline constexpr const T&
getYDerivative (const Dual<T,P> &x) { return x.partial(1); }
// Simple templated "copy" function
template<class T> inline void
template<class T> OSL_HOSTDEVICE inline void
assignment (T &a, T &b) { a = b; }
template<class T, int P> inline void
template<class T, int P> OSL_HOSTDEVICE inline void
assignment (T &a, Dual<T,P> &b) { a = b.val(); }
// Templated value equality. For scalars, it's the same as regular ==.
@@ -497,22 +500,22 @@ assignment (T &a, Dual<T,P> &b) { a = b.val(); }
// return if just their value is equal or if the whole struct (including
// derivs) are equal.
template<class T>
inline constexpr bool equalVal (const T &x, const T &y) {
OSL_HOSTDEVICE inline constexpr bool equalVal (const T &x, const T &y) {
return x == y;
}
template<class T, int P>
inline constexpr bool equalVal (const Dual<T,P> &x, const Dual<T,P> &y) {
OSL_HOSTDEVICE inline constexpr bool equalVal (const Dual<T,P> &x, const Dual<T,P> &y) {
return x.val() == y.val();
}
template<class T, int P>
inline constexpr bool equalVal (const Dual<T,P> &x, const T &y) {
OSL_HOSTDEVICE inline constexpr bool equalVal (const Dual<T,P> &x, const T &y) {
return x.val() == y;
}
template<class T, int P>
inline constexpr bool equalVal (const T &x, const Dual<T,P> &y) {
OSL_HOSTDEVICE inline constexpr bool equalVal (const T &x, const Dual<T,P> &y) {
return x == y.val();
}
@@ -523,7 +526,7 @@ inline constexpr bool equalVal (const T &x, const Dual<T,P> &y) {
// function f(scalar), then the dual function F(<u,u'>) is defined as:
// F(<u,u'>) = < f(u), f'(u)*u' >
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
dualfunc (const Dual<T,P>& u, const T& f_val, const T& df_val)
{
Dual<T,P> result;
@@ -539,7 +542,7 @@ dualfunc (const Dual<T,P>& u, const T& f_val, const T& df_val)
// F(<u,u'>, <v,v'>) = < f(u,v), dfdu(u,v)u' + dfdv(u,v)v' >
// (from http://en.wikipedia.org/wiki/Automatic_differentiation)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
dualfunc (const Dual<T,P>& u, const Dual<T,P>& v,
const T& f_val, const T& dfdu_val, const T& dfdv_val)
{
@@ -553,7 +556,7 @@ dualfunc (const Dual<T,P>& u, const Dual<T,P>& v,
// Helper for construction the result of a Dual function of three variables.
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
dualfunc (const Dual<T,P>& u, const Dual<T,P>& v, const Dual<T,P>& w,
const T& f_val, const T& dfdu_val, const T& dfdv_val, const T& dfdw_val)
{
@@ -568,7 +571,7 @@ dualfunc (const Dual<T,P>& u, const Dual<T,P>& v, const Dual<T,P>& w,
// f(x) = cos(x), f'(x) = -sin(x)
template<class T, int P>
inline Dual<T,P> cos (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> cos (const Dual<T,P> &a)
{
T sina, cosa;
OIIO::sincos(a.val(), &sina, &cosa);
@@ -576,7 +579,7 @@ inline Dual<T,P> cos (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_cos(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_cos(const Dual<T,P> &a)
{
T sina, cosa;
OIIO::fast_sincos (a.val(), &sina, &cosa);
@@ -585,7 +588,7 @@ inline Dual<T,P> fast_cos(const Dual<T,P> &a)
// f(x) = sin(x), f'(x) = cos(x)
template<class T, int P>
inline Dual<T,P> sin (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> sin (const Dual<T,P> &a)
{
T sina, cosa;
OIIO::sincos(a.val(), &sina, &cosa);
@@ -593,7 +596,7 @@ inline Dual<T,P> sin (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_sin(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_sin(const Dual<T,P> &a)
{
T sina, cosa;
OIIO::fast_sincos (a.val(), &sina, &cosa);
@@ -601,7 +604,7 @@ inline Dual<T,P> fast_sin(const Dual<T,P> &a)
}
template<class T, int P>
inline void sincos(const Dual<T,P> &a, Dual<T,P> *sine, Dual<T,P> *cosine)
OSL_HOSTDEVICE inline void sincos(const Dual<T,P> &a, Dual<T,P> *sine, Dual<T,P> *cosine)
{
T sina, cosa;
OIIO::sincos(a.val(), &sina, &cosa);
@@ -610,7 +613,7 @@ inline void sincos(const Dual<T,P> &a, Dual<T,P> *sine, Dual<T,P> *cosine)
}
template<class T, int P>
inline void fast_sincos(const Dual<T,P> &a, Dual<T,P> *sine, Dual<T,P> *cosine)
OSL_HOSTDEVICE inline void fast_sincos(const Dual<T,P> &a, Dual<T,P> *sine, Dual<T,P> *cosine)
{
T sina, cosa;
OIIO::fast_sincos(a.val(), &sina, &cosa);
@@ -620,7 +623,7 @@ inline void fast_sincos(const Dual<T,P> &a, Dual<T,P> *sine, Dual<T,P> *cosine)
// f(x) = tan(x), f'(x) = sec^2(x)
template<class T, int P>
inline Dual<T,P> tan (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> tan (const Dual<T,P> &a)
{
T tana = std::tan (a.val());
T cosa = std::cos (a.val());
@@ -629,7 +632,7 @@ inline Dual<T,P> tan (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_tan(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_tan(const Dual<T,P> &a)
{
T tana = OIIO::fast_tan (a.val());
T cosa = OIIO::fast_cos (a.val());
@@ -639,7 +642,7 @@ inline Dual<T,P> fast_tan(const Dual<T,P> &a)
// f(x) = cosh(x), f'(x) = sinh(x)
template<class T, int P>
inline Dual<T,P> cosh (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> cosh (const Dual<T,P> &a)
{
T f = std::cosh(a.val());
T df = std::sinh(a.val());
@@ -647,7 +650,7 @@ inline Dual<T,P> cosh (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_cosh(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_cosh(const Dual<T,P> &a)
{
T f = OIIO::fast_cosh(a.val());
T df = OIIO::fast_sinh(a.val());
@@ -657,7 +660,7 @@ inline Dual<T,P> fast_cosh(const Dual<T,P> &a)
// f(x) = sinh(x), f'(x) = cosh(x)
template<class T, int P>
inline Dual<T,P> sinh (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> sinh (const Dual<T,P> &a)
{
T f = std::sinh(a.val());
T df = std::cosh(a.val());
@@ -665,7 +668,7 @@ inline Dual<T,P> sinh (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_sinh(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_sinh(const Dual<T,P> &a)
{
T f = OIIO::fast_sinh(a.val());
T df = OIIO::fast_cosh(a.val());
@@ -674,7 +677,7 @@ inline Dual<T,P> fast_sinh(const Dual<T,P> &a)
// f(x) = tanh(x), f'(x) = sech^2(x)
template<class T, int P>
inline Dual<T,P> tanh (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> tanh (const Dual<T,P> &a)
{
T tanha = std::tanh(a.val());
T cosha = std::cosh(a.val());
@@ -683,7 +686,7 @@ inline Dual<T,P> tanh (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_tanh(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_tanh(const Dual<T,P> &a)
{
T tanha = OIIO::fast_tanh(a.val());
T cosha = OIIO::fast_cosh(a.val());
@@ -693,7 +696,7 @@ inline Dual<T,P> fast_tanh(const Dual<T,P> &a)
// f(x) = acos(x), f'(x) = -1/(sqrt(1 - x^2))
template<class T, int P>
inline Dual<T,P> safe_acos (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> safe_acos (const Dual<T,P> &a)
{
if (a.val() >= T(1))
return Dual<T,P> (T(0));
@@ -705,7 +708,7 @@ inline Dual<T,P> safe_acos (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_acos(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_acos(const Dual<T,P> &a)
{
T f = OIIO::fast_acos(a.val());
T df = fabsf(a.val()) < 1.0f ? -1.0f / sqrtf(1.0f - a.val() * a.val()) : 0.0f;
@@ -714,7 +717,7 @@ inline Dual<T,P> fast_acos(const Dual<T,P> &a)
// f(x) = asin(x), f'(x) = 1/(sqrt(1 - x^2))
template<class T, int P>
inline Dual<T,P> safe_asin (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> safe_asin (const Dual<T,P> &a)
{
if (a.val() >= T(1))
return Dual<T,P> (T(M_PI/2));
@@ -726,7 +729,7 @@ inline Dual<T,P> safe_asin (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_asin(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_asin(const Dual<T,P> &a)
{
T f = OIIO::fast_asin(a.val());
T df = fabsf(a.val()) < 1.0f ? 1.0f / sqrtf(1.0f - a.val() * a.val()) : 0.0f;
@@ -736,7 +739,7 @@ inline Dual<T,P> fast_asin(const Dual<T,P> &a)
// f(x) = atan(x), f'(x) = 1/(1 + x^2)
template<class T, int P>
inline Dual<T,P> atan (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> atan (const Dual<T,P> &a)
{
T f = std::atan (a.val());
T df = T(1) / (T(1) + a.val()*a.val());
@@ -744,7 +747,7 @@ inline Dual<T,P> atan (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_atan(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_atan(const Dual<T,P> &a)
{
T f = OIIO::fast_atan(a.val());
T df = 1.0f / (1.0f + a.val() * a.val());
@@ -756,7 +759,7 @@ inline Dual<T,P> fast_atan(const Dual<T,P> &a)
// reference: http://en.wikipedia.org/wiki/Atan2
// (above link has other formulations)
template<class T, int P>
inline Dual<T,P> atan2 (const Dual<T,P> &y, const Dual<T,P> &x)
OSL_HOSTDEVICE inline Dual<T,P> atan2 (const Dual<T,P> &y, const Dual<T,P> &x)
{
T atan2xy = std::atan2 (y.val(), x.val());
T denom = (x.val() == T(0) && y.val() == T(0)) ? T(0) : T(1) / (x.val()*x.val() + y.val()*y.val());
@@ -764,7 +767,7 @@ inline Dual<T,P> atan2 (const Dual<T,P> &y, const Dual<T,P> &x)
}
template<class T, int P>
inline Dual<T,P> fast_atan2(const Dual<T,P> &y, const Dual<T,P> &x)
OSL_HOSTDEVICE inline Dual<T,P> fast_atan2(const Dual<T,P> &y, const Dual<T,P> &x)
{
T atan2xy = OIIO::fast_atan2(y.val(), x.val());
T denom = (x.val() == 0 && y.val() == 0) ? 0.0f : 1.0f / (x.val() * x.val() + y.val() * y.val());
@@ -779,7 +782,7 @@ inline Dual<T,P> fast_atan2(const Dual<T,P> &y, const Dual<T,P> &x)
// (from http://en.wikipedia.org/wiki/Automatic_differentiation)
// so, pow(u,v) = < u^v, vu^(v-1) u' + log(u)u^v v' >
template<class T, int P>
inline Dual<T,P> safe_pow (const Dual<T,P> &u, const Dual<T,P> &v)
OSL_HOSTDEVICE inline Dual<T,P> safe_pow (const Dual<T,P> &u, const Dual<T,P> &v)
{
// NOTE: this function won't return exactly the same as pow(x,y) because we
// use the identity u^v=u * u^(v-1) which does not hold in all cases for our
@@ -791,7 +794,7 @@ inline Dual<T,P> safe_pow (const Dual<T,P> &u, const Dual<T,P> &v)
}
template<class T, int P>
inline Dual<T,P> fast_safe_pow(const Dual<T,P> &u, const Dual<T,P> &v)
OSL_HOSTDEVICE inline Dual<T,P> fast_safe_pow(const Dual<T,P> &u, const Dual<T,P> &v)
{
// NOTE: same issue as above (fast_safe_pow does even more clamping)
T powuvm1 = OIIO::fast_safe_pow (u.val(), v.val() - 1.0f);
@@ -803,7 +806,7 @@ inline Dual<T,P> fast_safe_pow(const Dual<T,P> &u, const Dual<T,P> &v)
// f(x) = log(a), f'(x) = 1/x
// (log base e)
template<class T, int P>
inline Dual<T,P> safe_log (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> safe_log (const Dual<T,P> &a)
{
T f = safe_log(a.val());
T df = a.val() < std::numeric_limits<T>::min() ? T(0) : T(1) / a.val();
@@ -811,7 +814,7 @@ inline Dual<T,P> safe_log (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_log(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_log(const Dual<T,P> &a)
{
T f = OIIO::fast_log(a.val());
T df = a.val() < std::numeric_limits<float>::min() ? 0.0f : 1.0f / a.val();
@@ -821,7 +824,7 @@ inline Dual<T,P> fast_log(const Dual<T,P> &a)
// f(x) = log2(x), f'(x) = 1/(x*log2)
// (log base 2)
template<class T, int P>
inline Dual<T,P> safe_log2 (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> safe_log2 (const Dual<T,P> &a)
{
T f = safe_log2(a.val());
T df = a.val() < std::numeric_limits<T>::min() ? T(0) : T(1) / (a.val() * T(M_LN2));
@@ -829,7 +832,7 @@ inline Dual<T,P> safe_log2 (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_log2(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_log2(const Dual<T,P> &a)
{
T f = OIIO::fast_log2(a.val());
T aln2 = a.val() * float(M_LN2);
@@ -840,7 +843,7 @@ inline Dual<T,P> fast_log2(const Dual<T,P> &a)
// f(x) = log10(x), f'(x) = 1/(x*log10)
// (log base 10)
template<class T, int P>
inline Dual<T,P> safe_log10 (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> safe_log10 (const Dual<T,P> &a)
{
T f = safe_log10(a.val());
T df = a.val() < std::numeric_limits<T>::min() ? T(0) : T(1) / (a.val() * T(M_LN10));
@@ -848,7 +851,7 @@ inline Dual<T,P> safe_log10 (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_log10(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_log10(const Dual<T,P> &a)
{
T f = OIIO::fast_log10(a.val());
T aln10 = a.val() * float(M_LN10);
@@ -858,14 +861,14 @@ inline Dual<T,P> fast_log10(const Dual<T,P> &a)
// f(x) = e^x, f'(x) = e^x
template<class T, int P>
inline Dual<T,P> exp (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> exp (const Dual<T,P> &a)
{
T f = std::exp(a.val());
return dualfunc (a, f, f);
}
template<class T, int P>
inline Dual<T,P> fast_exp(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_exp(const Dual<T,P> &a)
{
T f = OIIO::fast_exp(a.val());
return dualfunc (a, f, f);
@@ -873,7 +876,7 @@ inline Dual<T,P> fast_exp(const Dual<T,P> &a)
// f(x) = 2^x, f'(x) = (2^x)*log(2)
template<class T, int P>
inline Dual<T,P> exp2 (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> exp2 (const Dual<T,P> &a)
{
using std::exp2;
T f = exp2(a.val());
@@ -881,7 +884,7 @@ inline Dual<T,P> exp2 (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_exp2(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_exp2(const Dual<T,P> &a)
{
T f = OIIO::fast_exp2(float(a.val()));
return dualfunc (a, f, f*T(M_LN2));
@@ -890,7 +893,7 @@ inline Dual<T,P> fast_exp2(const Dual<T,P> &a)
// f(x) = e^x - 1, f'(x) = e^x
template<class T, int P>
inline Dual<T,P> expm1 (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> expm1 (const Dual<T,P> &a)
{
using std::expm1;
T f = expm1(a.val());
@@ -899,7 +902,7 @@ inline Dual<T,P> expm1 (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_expm1(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_expm1(const Dual<T,P> &a)
{
T f = OIIO::fast_expm1(a.val());
T df = OIIO::fast_exp (a.val());
@@ -908,7 +911,7 @@ inline Dual<T,P> fast_expm1(const Dual<T,P> &a)
// f(x) = erf(x), f'(x) = (2e^(-x^2))/sqrt(pi)
template<class T, int P>
inline Dual<T,P> erf (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> erf (const Dual<T,P> &a)
{
using std::erf;
T f = erf (a.val());
@@ -918,7 +921,7 @@ inline Dual<T,P> erf (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_erf(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_erf(const Dual<T,P> &a)
{
T f = OIIO::fast_erf (float(a.val())); // float version!
const T two_over_sqrt_pi = 1.128379167095512573896158903f;
@@ -928,7 +931,7 @@ inline Dual<T,P> fast_erf(const Dual<T,P> &a)
// f(x) = erfc(x), f'(x) = -(2e^(-x^2))/sqrt(pi)
template<class T, int P>
inline Dual<T,P> erfc (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> erfc (const Dual<T,P> &a)
{
using std::erfc;
T f = erfc (a.val()); // float version!
@@ -938,7 +941,7 @@ inline Dual<T,P> erfc (const Dual<T,P> &a)
}
template<class T, int P>
inline Dual<T,P> fast_erfc(const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> fast_erfc(const Dual<T,P> &a)
{
T f = OIIO::fast_erfc (float(a.val())); // float version!
const T two_over_sqrt_pi = -1.128379167095512573896158903f;
@@ -949,7 +952,7 @@ inline Dual<T,P> fast_erfc(const Dual<T,P> &a)
// f(x) = sqrt(x), f'(x) = 1/(2*sqrt(x))
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P> sqrt (const Dual<T,P> &a)
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P> sqrt (const Dual<T,P> &a)
{
if (a.val() <= T(0))
return Dual<T,P> (T(0));
@@ -960,7 +963,7 @@ inline OIIO_CONSTEXPR14 Dual<T,P> sqrt (const Dual<T,P> &a)
// f(x) = 1/sqrt(x), f'(x) = -1/(2*x^(3/2))
template<class T, int P>
inline Dual<T,P> inversesqrt (const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> inversesqrt (const Dual<T,P> &a)
{
// do we want to print an error message?
if (a.val() <= T(0))
@@ -972,21 +975,21 @@ inline Dual<T,P> inversesqrt (const Dual<T,P> &a)
// (fx) = x*(1-a) + y*a, f'(x) = (1-a)x' + (y - x)*a' + a*y'
template<class T, int P>
inline Dual<T,P> mix (const Dual<T,P> &x, const Dual<T,P> &y, const Dual<T,P> &a)
OSL_HOSTDEVICE inline Dual<T,P> mix (const Dual<T,P> &x, const Dual<T,P> &y, const Dual<T,P> &a)
{
T mixval = x.val()*(T(1)-a.val()) + y.val()*a.val();
return dualfunc (x, y, a, mixval, T(1)-a.val(), a.val(), y.val() - x.val());
}
template<class T, int P>
inline Dual<T,P> fabs (const Dual<T,P> &x)
OSL_HOSTDEVICE inline Dual<T,P> fabs (const Dual<T,P> &x)
{
return x.val() >= T(0) ? x : -x;
}
inline float smoothstep(float e0, float e1, float x) {
OSL_HOSTDEVICE inline float smoothstep(float e0, float e1, float x) {
if (x < e0) return 0.0f;
else if (x >= e1) return 1.0f;
else {
@@ -997,7 +1000,7 @@ inline float smoothstep(float e0, float e1, float x) {
// f(t) = (3-2t)t^2, t = (x-e0)/(e1-e0)
template<class T, int P>
inline Dual<T,P> smoothstep (const Dual<T,P> &e0, const Dual<T,P> &e1, const Dual<T,P> &x)
OSL_HOSTDEVICE inline Dual<T,P> smoothstep (const Dual<T,P> &e0, const Dual<T,P> &e1, const Dual<T,P> &x)
{
if (x.val() < e0.val()) {
return Dual<T,P> (T(0));
@@ -1013,7 +1016,7 @@ inline Dual<T,P> smoothstep (const Dual<T,P> &e0, const Dual<T,P> &e1, const Dua
// ceil(Dual) loses derivatives
template<class T, int P>
inline constexpr float ceil (const Dual<T,P> &x)
OSL_HOSTDEVICE inline constexpr float ceil (const Dual<T,P> &x)
{
return std::ceil(x.val());
}
@@ -1021,7 +1024,7 @@ inline constexpr float ceil (const Dual<T,P> &x)
// floor(Dual) loses derivatives
template<class T, int P>
inline constexpr float floor (const Dual<T,P> &x)
OSL_HOSTDEVICE inline constexpr float floor (const Dual<T,P> &x)
{
return std::floor(x.val());
}
@@ -1029,7 +1032,7 @@ inline constexpr float floor (const Dual<T,P> &x)
// floor, cast to an int.
template<class T, int P>
inline constexpr int
OSL_HOSTDEVICE inline constexpr int
ifloor (const Dual<T,P> &x)
{
return (int)floor(x);
+25 -25
View File
@@ -78,14 +78,14 @@ template<> struct ScalarFromVec<Dual2<Color3>> { typedef Dual2<Float> type; };
/// A uniform way to assemble a Vec3 from float and a Dual<Vec3>
/// from Dual<float>.
inline Vec3
OSL_HOSTDEVICE inline Vec3
make_Vec3 (float x, float y, float z)
{
return Vec3 (x, y, z);
}
template<class T, int P>
inline Dual<Imath::Vec3<T>,P>
OSL_HOSTDEVICE inline Dual<Imath::Vec3<T>,P>
make_Vec3 (const Dual<T,P> &x, const Dual<T,P> &y, const Dual<T,P> &z)
{
Dual<Imath::Vec3<T>,P> result;
@@ -98,7 +98,7 @@ make_Vec3 (const Dual<T,P> &x, const Dual<T,P> &y, const Dual<T,P> &z)
/// Make a Dual<Vec3> from a single Dual<Float> x coordinate, and 0
/// for the other components.
template<class T, int P>
inline Dual<Imath::Vec3<T>,P>
OSL_HOSTDEVICE inline Dual<Imath::Vec3<T>,P>
make_Vec3 (const Dual<T,P> &x)
{
Dual<Imath::Vec3<T>,P> result;
@@ -109,7 +109,7 @@ make_Vec3 (const Dual<T,P> &x)
template<class T, int P>
inline Dual<Imath::Vec3<T>,P>
OSL_HOSTDEVICE inline Dual<Imath::Vec3<T>,P>
make_Vec3 (const Dual<T,P> &x, const Dual<T,P> &y)
{
Dual<Imath::Vec3<T>,P> result;
@@ -122,14 +122,14 @@ make_Vec3 (const Dual<T,P> &x, const Dual<T,P> &y)
/// A uniform way to assemble a Color3 from float and a Dual<Color3>
/// from Dual<float>.
inline Color3
OSL_HOSTDEVICE inline Color3
make_Color3 (float x, float y, float z)
{
return Color3 (x, y, z);
}
template<class T, int P>
inline Dual<Imath::Color3<T>,P>
OSL_HOSTDEVICE inline Dual<Imath::Color3<T>,P>
make_Color3 (const Dual<T,P> &x, const Dual<T,P> &y, const Dual<T,P> &z)
{
Dual<Imath::Color3<T>,P> result;
@@ -142,14 +142,14 @@ make_Color3 (const Dual<T,P> &x, const Dual<T,P> &y, const Dual<T,P> &z)
/// A uniform way to assemble a Vec2 from float and a Dual<Vec2>
/// from Dual<float>.
inline Vec2
OSL_HOSTDEVICE inline Vec2
make_Vec2 (float x, float y)
{
return Vec2 (x, y);
}
template<class T, int P>
inline Dual<Imath::Vec2<T>,P>
OSL_HOSTDEVICE inline Dual<Imath::Vec2<T>,P>
make_Vec2 (const Dual<T,P> &x, const Dual<T,P> &y)
{
Dual<Imath::Vec2<T>,P> result;
@@ -167,7 +167,7 @@ make_Vec2 (const Dual<T,P> &x, const Dual<T,P> &y)
/// comp(Dual<Vec3>,c) returns a Dual<float> of the c-th component (with
/// derivs).
inline float
OSL_HOSTDEVICE inline float
comp (const Vec3 &v, int c)
{
return v[c];
@@ -175,7 +175,7 @@ comp (const Vec3 &v, int c)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
comp (const Dual<Imath::Vec3<T>,P> &v, int c)
{
Dual<T,P> result;
@@ -187,7 +187,7 @@ comp (const Dual<Imath::Vec3<T>,P> &v, int c)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
comp (const Dual<Imath::Color3<T>,P> &v, int c)
{
Dual<T,P> result;
@@ -197,7 +197,7 @@ comp (const Dual<Imath::Color3<T>,P> &v, int c)
}
inline float
OSL_HOSTDEVICE inline float
comp (const Vec2 &v, int c)
{
return v[c];
@@ -205,7 +205,7 @@ comp (const Vec2 &v, int c)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
comp (const Dual<Imath::Vec2<T>,P> &v, int c)
{
Dual<T,P> result;
@@ -334,7 +334,7 @@ multDirMatrix (const Imath::Matrix44<S> &M,
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
dot (const Dual<Imath::Vec3<T>,P> &a, const Dual<Imath::Vec3<T>,P> &b)
{
auto ax = comp (a, 0);
@@ -349,7 +349,7 @@ dot (const Dual<Imath::Vec3<T>,P> &a, const Dual<Imath::Vec3<T>,P> &b)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
dot (const Dual<Imath::Vec3<T>,P> &a, const Imath::Vec3<T> &b)
{
auto ax = comp (a, 0);
@@ -364,7 +364,7 @@ dot (const Dual<Imath::Vec3<T>,P> &a, const Imath::Vec3<T> &b)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
dot (const Imath::Vec3<T> &a, const Dual<Imath::Vec3<T>,P> &b)
{
return dot (b, a);
@@ -373,7 +373,7 @@ dot (const Imath::Vec3<T> &a, const Dual<Imath::Vec3<T>,P> &b)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
dot (const Dual<Imath::Vec2<T>,P> &a, const Dual<Imath::Vec2<T>,P> &b)
{
auto ax = comp (a, 0);
@@ -386,7 +386,7 @@ dot (const Dual<Imath::Vec2<T>,P> &a, const Dual<Imath::Vec2<T>,P> &b)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
dot (const Dual<Imath::Vec2<T>,P> &a, const Vec2 &b)
{
auto ax = comp (a, 0);
@@ -399,7 +399,7 @@ dot (const Dual<Imath::Vec2<T>,P> &a, const Vec2 &b)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
dot (const Vec2 &a, const Dual<Imath::Vec2<T>,P> &b)
{
auto ax = comp (a, 0);
@@ -412,7 +412,7 @@ dot (const Vec2 &a, const Dual<Imath::Vec2<T>,P> &b)
template<class T, int P>
inline Dual<Imath::Vec3<T>,P>
OSL_HOSTDEVICE inline Dual<Imath::Vec3<T>,P>
cross (const Dual<Imath::Vec3<T>,P> &a, const Dual<Imath::Vec3<T>,P> &b)
{
auto ax = comp (a, 0);
@@ -430,7 +430,7 @@ cross (const Dual<Imath::Vec3<T>,P> &a, const Dual<Imath::Vec3<T>,P> &b)
template<class T, int P>
inline OIIO_CONSTEXPR14 Dual<T,P>
OSL_HOSTDEVICE inline OIIO_CONSTEXPR14 Dual<T,P>
length (const Dual<Imath::Vec3<T>,P> &a)
{
auto ax = comp (a, 0);
@@ -442,7 +442,7 @@ length (const Dual<Imath::Vec3<T>,P> &a)
template<class T, int P>
inline Dual<Imath::Vec3<T>,P>
OSL_HOSTDEVICE inline Dual<Imath::Vec3<T>,P>
normalize (const Dual<Imath::Vec3<T>,P> &a)
{
auto ax = comp (a, 0);
@@ -463,7 +463,7 @@ normalize (const Dual<Imath::Vec3<T>,P> &a)
template<class T, int P>
inline Dual<T,P>
OSL_HOSTDEVICE inline Dual<T,P>
distance (const Dual<Imath::Vec3<T>,P> &a, const Dual<Imath::Vec3<T>,P> &b)
{
return length (a - b);
@@ -471,7 +471,7 @@ distance (const Dual<Imath::Vec3<T>,P> &a, const Dual<Imath::Vec3<T>,P> &b)
template<class T, int P>
inline Dual<T,P>
OSL_HOSTDEVICE inline Dual<T,P>
distance (const Dual<Imath::Vec3<T>,P> &a, const Imath::Vec3<T> &b)
{
return length (a - b);
@@ -479,7 +479,7 @@ distance (const Dual<Imath::Vec3<T>,P> &a, const Imath::Vec3<T> &b)
template<class T, int P>
inline Dual<T,P>
OSL_HOSTDEVICE inline Dual<T,P>
distance (const Imath::Vec3<T> &a, const Dual<Imath::Vec3<T>,P> &b)
{
return length (a - b);
+6
View File
@@ -103,3 +103,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#else
# define OSLQUERYPUBLIC OSL_DLL_IMPORT
#endif
#if defined(oslnoise_EXPORTS) || defined(oslexec_EXPORTS)
# define OSLNOISEPUBLIC OSL_DLL_EXPORT
#else
# define OSLNOISEPUBLIC OSL_DLL_IMPORT
#endif
+19 -3
View File
@@ -43,7 +43,7 @@ namespace llvm {
class ExecutionEngine;
class Function;
class FunctionType;
class JITMemoryManager;
class SectionMemoryManager;
class Linker;
class LLVMContext;
class Module;
@@ -322,6 +322,10 @@ public:
/// data type, return the llvm::Value of the new pointer.
llvm::Value *ptr_cast (llvm::Value* val, const OIIO::TypeDesc &type);
/// Cast the variable specified by val to a pointer of type void*,
/// return the llvm::Value of the new pointer.
llvm::Value *int_to_ptr_cast (llvm::Value* val);
/// Cast the pointer variable specified by val to a pointer of type
/// void* return the llvm::Value of the new pointer.
llvm::Value *void_ptr (llvm::Value* val);
@@ -410,6 +414,10 @@ public:
/// Generate code for a memcpy.
void op_memcpy (llvm::Value *dst, llvm::Value *src, int len, int align=1);
/// Generate code for a memcpy.
void op_memcpy (llvm::Value *dst, int dstalign,
llvm::Value *src, int srcalign, int len);
/// Dereference a pointer: return *ptr
llvm::Value *op_load (llvm::Value *ptr);
@@ -448,6 +456,7 @@ public:
llvm::Value *op_int_to_float (llvm::Value *a);
llvm::Value *op_bool_to_int (llvm::Value *a);
llvm::Value *op_float_to_double (llvm::Value *a);
llvm::Value *op_int_to_longlong (llvm::Value *a);
llvm::Value *op_and (llvm::Value *a, llvm::Value *b);
llvm::Value *op_or (llvm::Value *a, llvm::Value *b);
@@ -474,7 +483,14 @@ public:
/// file. If err is not NULL, errors will be deposited there.
void write_bitcode_file (const char *filename, std::string *err=NULL);
/// Convert a function's bitcode to a string.
/// Generate PTX for the current Module and return it as a string
bool ptx_compile_group (llvm::Module* lib_module, const std::string& name,
std::string& out);
/// Convert a whole module's bitcode to a string.
std::string bitcode_string (llvm::Module *module);
/// Convert one function's bitcode to a string.
std::string bitcode_string (llvm::Function *func);
/// Delete the IR for the body of the given function to reclaim its
@@ -500,7 +516,7 @@ private:
llvm::LLVMContext *m_llvm_context;
llvm::Module *m_llvm_module;
IRBuilder *m_builder;
MemoryManager *m_llvm_jitmm;
llvm::SectionMemoryManager *m_llvm_jitmm;
llvm::Function *m_current_function;
llvm::legacy::PassManager *m_llvm_module_passes;
llvm::legacy::FunctionPassManager *m_llvm_func_passes;
+11 -14
View File
@@ -114,29 +114,26 @@ struct OSLEXECPUBLIC ClosureColor {
/// ClosureComponent is a subclass of ClosureColor that holds the ID and
/// parameter data for a single primitive closure component (such as
/// diffuse, translucent, etc.). The declaration leaves 4 bytes for
/// parameter data (mem), but it's expected that the structure be
/// allocated with enough space to house all the parameter data for
/// whatever type of custom primitive component it actually is.
struct OSLEXECPUBLIC ClosureComponent : public ClosureColor
/// diffuse, translucent, etc.).
///
/// ClosureComponent itself takes up 16 bytes, and its allocation will be
/// scaled to add parameters after the end of the struct. Alignment is
/// set to 16 bytes so that 64 bit pointers and 128 bit SSE types in user
/// structs have the required alignment.
struct OSLEXECPUBLIC OSL_ALIGNAS(16) ClosureComponent : public ClosureColor
{
Vec3 w; ///< Weight of this component
alignas(void*) char mem[8]; ///< Memory for the primitive, 8 is the minimum, allocation will be
/// scaled to requirements of the registered closure struct.
/// Alignment is forced to a void* to match likely alignement requirements
/// of the user's structs.
/// Handy method for getting the parameter memory as a void*.
///
void *data () { return &mem; }
const void *data () const { return &mem; }
void *data () { return (char*)(this + 1); }
const void *data () const { return (const char*)(this + 1); }
/// Handy methods for extracting the underlying parameters as a struct
template <typename T>
const T* as() const { return reinterpret_cast<const T*>(mem); }
const T* as() const { return reinterpret_cast<const T*>(data()); }
template <typename T>
T* as() { return reinterpret_cast<const T*>(mem); }
T* as() { return reinterpret_cast<const T*>(data()); }
};
+10 -4
View File
@@ -47,18 +47,24 @@ public:
OSLCompiler (ErrorHandler *errhandler=NULL);
~OSLCompiler ();
/// Compile the given file, using the list of command-line options.
/// Compile the given file, using the list of command-line options. The
/// stdoslpath parameter provides a custom path for finding stdosl.h.
/// Return true if ok, false if the compile failed.
bool compile (string_view filename,
const std::vector<std::string> &options,
string_view stdoslpath = string_view());
/// Compile the given source code buffer, using the list of command-line
/// options, placing the resulting "oso" in osobuffer. Return true if
/// ok, false if the compile failed.
/// options, placing the resulting "oso" in osobuffer. The stdoslpath
/// parameter provides a custom path for finding stdosl.h. The filename
/// optionally provides a name for the buffer, used for error reporting
/// (the compile() from file method would have used the name of the
/// actual file for this purpose). Return true if ok, false if the
/// compile failed.
bool compile_buffer (string_view sourcecode, std::string &osobuffer,
const std::vector<std::string> &options,
string_view stdoslpath = string_view());
string_view stdoslpath = string_view(),
string_view filename = string_view());
/// Return the name of our compiled output (must be called after
/// compile()).
+82 -13
View File
@@ -44,21 +44,56 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// same if another packages is compiling against OSL and using these headers
// (OSL may be C++11 but the client package may be older, or vice versa --
// use these two symbols to differentiate these cases, when important).
#if (__cplusplus >= 201402L)
# define OSL_CPLUSPLUS_VERSION 14
#if (__cplusplus >= 201703L)
# define OSL_CPLUSPLUS_VERSION 17
# define OSL_CONSTEXPR14 constexpr
# define OSL_CONSTEXPR17 constexpr
# define OSL_CONSTEXPR20 /* not constexpr before C++20 */
#elif (__cplusplus >= 201402L)
# define OSL_CPLUSPLUS_VERSION 14
# define OSL_CONSTEXPR14 constexpr
# define OSL_CONSTEXPR17 /* not constexpr before C++17 */
# define OSL_CONSTEXPR20 /* not constexpr before C++20 */
#elif (__cplusplus >= 201103L) || _MSC_VER >= 1900
# define OSL_CPLUSPLUS_VERSION 11
# define OSL_CPLUSPLUS_VERSION 11
# define OSL_CONSTEXPR14 /* not constexpr before C++14 */
# define OSL_CONSTEXPR17 /* not constexpr before C++17 */
# define OSL_CONSTEXPR20 /* not constexpr before C++20 */
#else
# error "This version of OSL requires C++11"
# error "This version of OSL requires C++11"
#endif
#ifndef OSL_HOSTDEVICE
# ifdef __CUDACC__
# define OSL_HOSTDEVICE __host__ __device__
# else
# define OSL_HOSTDEVICE
# endif
#endif
#ifndef OSL_DEVICE
# ifdef __CUDA_ARCH__
# define OSL_DEVICE __device__
# else
# define OSL_DEVICE
# endif
#endif
// Symbol export defines
#include "export.h"
// All the things we need from Imath
#include <OpenEXR/ImathVec.h>
#ifdef __CUDACC__
// When compiling for CUDA, we need to make sure the modified Imath
// headers are included before the stock versions.
# include <OSL/ImathVec_cuda.h>
# include <OSL/ImathMatrix_cuda.h>
#else
# include <OpenEXR/ImathVec.h>
# include <OpenEXR/ImathMatrix.h>
#endif
#include <OpenEXR/ImathColor.h>
#include <OpenEXR/ImathMatrix.h>
// All the things we need from OpenImageIO
#include <OpenImageIO/oiioversion.h>
@@ -68,6 +103,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <OpenImageIO/ustring.h>
#include <OpenImageIO/platform.h>
// Make sure we can use OIIO::cspan
#if OIIO_VERSION >= 10904
# include <OpenImageIO/span.h>
#else
# include <OpenImageIO/array_view.h>
#endif
// Extensions to Imath
#include <OSL/matrix22.h>
@@ -114,21 +156,48 @@ using OIIO::ustring;
using OIIO::ustringHash;
using OIIO::string_view;
#ifndef __has_attribute
# define __has_attribute(x) 0
// Make sure we can use OIIO::cspan
#if OIIO_VERSION >= 10904
using OIIO::cspan;
#else
template<typename T> using cspan = OIIO::array_view<const T>;
#endif
#if OSL_CPLUSPLUS_VERSION >= 14 && __has_attribute(deprecated)
// In C++20 (and some compilers before that), __has_cpp_attribute can
// test for understand of [[attr]] tests.
#ifndef __has_cpp_attribute
# define __has_cpp_attribute(x) 0
#endif
// On gcc & clang, __has_attribute can test for __attribute__((attr))
#ifndef __has_attribute
# define __has_attribute(x) 0
#endif
// In C++17 (and some compilers before that), __has_include("blah.h") or
// __has_include(<blah.h>) can test for presence of an include file.
#ifndef __has_include
# define __has_include(x) 0
#endif
#if OSL_CPLUSPLUS_VERSION >= 14 || __has_cpp_attribute(deprecated)
# define OSL_DEPRECATED(msg) [[deprecated(msg)]]
#elif (defined(__GNUC__) && OIIO_GNUC_VERSION >= 40600) || defined(__clang__)
#elif defined(__GNUC__) || defined(__clang__) || __has_attribute(deprecated)
# define OSL_DEPRECATED(msg) __attribute__((deprecated(msg)))
#elif defined(__GNUC__) /* older gcc -- only the one with no message */
# define OSL_DEPRECATED(msg) __attribute__((deprecated))
#elif defined(_MSC_VER)
# define OSL_DEPRECATED(msg) __declspec(deprecated(msg))
#else
# define OSL_DEPRECATED(msg)
#endif
/// Work around bug in GCC with mixed __attribute__ and alignas parsing
/// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69585
#ifdef __GNUC__
# define OSL_ALIGNAS(size) __attribute__((aligned(size)))
#else
# define OSL_ALIGNAS(size) alignas(size)
#endif
OSL_NAMESPACE_EXIT
+53 -17
View File
@@ -37,6 +37,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <OpenImageIO/refcnt.h>
#include <OpenImageIO/ustring.h>
#include <OpenImageIO/array_view.h>
#if OPENIMAGEIO_VERSION <= 10902
#include <OpenImageIO/imagebufalgo_util.h>
#endif
OSL_NAMESPACE_ENTER
@@ -80,6 +83,7 @@ public:
/// 1. Attributes that should be exposed to users:
/// int statistics:level Automatically print OSL statistics (0).
/// string searchpath:shader Colon-separated path to search for .oso
/// files ("", meaning test "." only)
/// string colorspace Name of RGB color space ("Rec709")
/// int range_checking Generate extra code for component & array
/// range checking (1)
@@ -111,6 +115,9 @@ public:
/// fails to find the layer or parameter? (1)
/// int strict_messages Issue error if a message is set after
/// being queried (1).
/// int error_repeats If zero, suppress repeats of errors and
/// warnings that are exact duplicates of
/// earlier ones. (1)
/// int lazylayers Evaluate shader layers only when their
/// outputs are first needed (1)
/// int lazyglobals Run layers lazily even if they write to
@@ -128,6 +135,8 @@ public:
/// means a param CANNOT be overridden by
/// interpolated geometric parameters.
/// int countlayerexecs Add extra code to count total layers run.
/// int allow_shader_replacement Allow shader to be specified more than
/// once, replacing former definition.
/// string archive_groupname Name of a group to pickle and archive.
/// string archive_filename Name of file to save the group archive.
/// 3. Attributes that that are intended for developers debugging
@@ -152,6 +161,8 @@ public:
/// layer functions.
/// int llvm_debug_ops Extra printfs for each OSL op (helpful
/// for devs to find crashes)
/// int llvm_output_bitcode Output the full bitcode for each group,
/// for debugging. (0)
/// int max_local_mem_KB Error if shader group needs more than this
/// much local storage to execute (1024K)
/// string debug_groupname Name of shader group -- debug only this one
@@ -267,6 +278,12 @@ public:
/// int unknown_closures_needed Nonzero if additional closures may be
/// needed, whose names can't be known
/// without actually running the shader.
/// int globals_read Bitfield ("or'ed" SGBits values) of
/// which ShaderGlobals may be read by
/// by the shader group.
/// int globals_write Bitfield ("or'ed" SGBits values) of
/// which ShaderGlobals may be written by
/// by the shader group.
/// int num_globals_needed The number of named globals needed.
/// ptr globals_needed Retrieves a pointer to the ustring array
/// containing all globals needed.
@@ -392,14 +409,25 @@ public:
bool Parameter (string_view name, TypeDesc t, const void *val,
bool lockgeom);
/// Create a new shader instance, either replacing the one for the
/// specified usage (if not within a group) or appending to the
/// current group (if a group has been started).
/// Create a new shader instance, either replacing the current group (if
/// not within a group) or appending to the current group (if a group
/// has been started).
bool Shader (string_view shaderusage,
string_view shadername = string_view(),
string_view layername = string_view());
string_view shadername,
string_view layername);
/// Connect two shaders within the current group
/// Connect two shaders within the current group. The source layer must
/// be *upstream* of down destination layer (i.e. source must be
/// declared earlier within the shader group). The named parameters must
/// be of compatible type -- float to float, color to color, array to
/// array of the same length and element type, etc. In general, it is
/// permissible to connect type A to type B if and only if it is allowed
/// within OSL to assign an A to a B (i.e., if `A = B` is legal). So any
/// "triple" may be connected to any other triple, and a float output
/// may be connected to a triple input (but not the other way around).
/// It is permitted to connect a single component of an aggregate to a
/// float and vice versa, for example,
/// `ConnectShaders ("lay1", "mycolorout[2]", "lay2", "myfloatinput")`
///
bool ConnectShaders (string_view srclayer, string_view srcparam,
string_view dstlayer, string_view dstparam);
@@ -449,9 +477,6 @@ public:
/// setup, don't actually run the shader.
bool execute (ShadingContext *ctx, ShaderGroup &group,
ShaderGlobals &globals, bool run=true);
OSL_DEPRECATED("Deprecated since 1.6, pass context pointer, not reference.")
bool execute (ShadingContext &ctx, ShaderGroup &group,
ShaderGlobals &globals, bool run=true);
/// Bind a shader group and globals to the context, in preparation to
/// execute, including optimization and JIT of the group (if it has not
@@ -552,6 +577,13 @@ public:
bool query_closure (const char **name, int *id,
const ClosureParam **params);
/// For the proposed shader "global" name, return the corresponding
/// SGBits enum.
static SGBits globals_bit (ustring name);
/// For the SGBits value, return the shader "globals" name.
static ustring globals_name (SGBits bit);
/// For the proposed raytype name, return the bit pattern that
/// describes it, or 0 for an unrecognized name. (This retrieves
/// data passed in via attribute("raytypes")).
@@ -564,14 +596,17 @@ public:
/// to the optimizer, and will be determined strictly at execution time.
void set_raytypes(ShaderGroup *group, int raytypes_on, int raytypes_off);
/// Ensure that the group has been optimized and JITed.
/// Ensure that the group has been optimized and JITed.
void optimize_group (ShaderGroup *group);
/// Ensure that the group has been optimized and JITed. The ctx pointer
/// optionally supplies a ShadingContext to use; if one is not supplied,
/// one will be temporarily allocated if needed.
void optimize_group (ShaderGroup *group, ShadingContext *ctx = nullptr);
/// Ensure that the group has been optimized and JITed. This is a
/// convenience function that simply calls set_raytypes followed by optimize_group.
/// convenience function that simply calls set_raytypes followed by
/// optimize_group. The ctx optionally supplies a ShadingContext to use;
/// if not supplied, one will be temporarily allocated if needed.
void optimize_group (ShaderGroup *group, int raytypes_on,
int raytypes_off);
int raytypes_off, ShadingContext *ctx = nullptr);
/// If option "greedyjit" was set, this call will trigger all
/// shader groups that have not yet been compiled to do so with the
@@ -621,9 +656,9 @@ private:
#ifdef OPENIMAGEIO_IMAGEBUF_H
#ifdef OPENIMAGEIO_IMAGEBUFALGO_H
// To keep from polluting all OSL clients with ImageBuf & ROI, only expose
// the following declarations if they have included OpenImageIO/imagebuf.h.
// the following declarations if they have included OpenImageIO/imagebufalgo.h.
// enum describing where shades are located for shade_image().
enum ShadeImageLocations {
@@ -656,7 +691,8 @@ bool shade_image (ShadingSystem &shadingsys, ShaderGroup &group,
const ShaderGlobals *defaultsg,
OIIO::ImageBuf &buf, OIIO::array_view<ustring> outputs,
ShadeImageLocations shadelocations = ShadePixelCenters,
OIIO::ROI roi = OIIO::ROI(), int nthreads = 0);
OIIO::ROI roi = OIIO::ROI(),
OIIO::ImageBufAlgo::parallel_image_options popt = 0);
#endif
+386 -354
View File
File diff suppressed because it is too large Load Diff
+157 -74
View File
@@ -54,100 +54,152 @@ namespace pvt {
/// <doc OSLQuery>
/// **OSLQuery Documentation**
///
///
/// Introduction and Tutorial
/// =========================
///
/// `OSLQuery` is a class that lets an application interrogate a
/// compiled shader for information about its parameters.
///
/// The shader may be an already-compiled shader file on disk (i.e. a
/// `.oso` file), or the `.oso` equivalent in a string, or the binary
/// representation used by the OSL `ShaderSystem` runtime (as a pointer
/// to a `ShaderGroup`). For example,
///
/// ~~~
/// OSLQuery oslquery ("polished_oak");
/// ~~~
///
/// It's then easy to retrieve a specific parameter:
///
/// ~~~
/// int nparams = oslquery.nparams(); // number of params
///
/// const OSLQuery::Parameter *param;
/// p = oslquery.getparam (i); // by index (0..nparams-1)
/// p = oslquery.getparam ("woodcolor"); // by name
/// ~~~
///
/// And the `Parameter` structure will hold all the information you need
/// about that paramter. For example:
///
/// ~~~
/// std::cout << "Parameter " << p->name
/// << " is type " << p->type << "\n"
/// ~~~
///
/// You can find out if the parameter is a closure, an output parameter,
/// etc. You can also find out its default values, which are stored in
/// vector fields `idefault`, `fdefault`, and `sdefault` depending on
/// whether the types is based on int, float, or string, respectively.
///
///
/// OSLQuery class API Reference
/// ============================
class OSLQUERYPUBLIC OSLQuery {
public:
/// Parameter holds all the information about a single shader parameter.
///
struct Parameter {
ustring name; ///< name
TypeDesc type; ///< data type
bool isoutput; ///< is it an output param?
bool validdefault; ///< false if there's no default val
bool varlenarray; ///< is it a varying-length array?
bool isstruct; ///< is it a structure?
bool isclosure; ///< is it a closure?
void *data; ///< pointer to data
std::vector<int> idefault; ///< default int values
std::vector<float> fdefault; ///< default float values
std::vector<ustring> sdefault; ///< default string values
std::vector<ustring> spacename; ///< space name for matrices and
///< triples, for each array elem.
std::vector<ustring> fields; ///< Names of this struct's fields
ustring structname; ///< Name of the struct
std::vector<Parameter> metadata; ///< Meta-data about the param
Parameter ()
: isoutput(false), validdefault(false), varlenarray(false),
isstruct(false), isclosure(false), data(NULL)
{ }
/// Parameter helper structure
/// --------------------------
/// `Parameter` holds all the information about a single shader
/// parameter.
/// <code>
struct OSLQUERYPUBLIC Parameter {
ustring name; //< name
TypeDesc type; //< data type
bool isoutput = false; //< is it an output param?
bool validdefault = false; //< false if there's no default val
bool varlenarray = false; //< is it a varying-length array?
bool isstruct = false; //< is it a structure?
bool isclosure = false; //< is it a closure?
void *data = nullptr; //< pointer to data
std::vector<int> idefault; //< default int values
std::vector<float> fdefault; //< default float values
std::vector<ustring> sdefault; //< default string values
std::vector<ustring> spacename; //< space name for matrices and
//< triples, for each array elem.
std::vector<ustring> fields; //< Names of this struct's fields
ustring structname; //< Name of the struct
std::vector<Parameter> metadata; //< Meta-data about the param
Parameter () {}
Parameter (const Parameter& src);
Parameter (Parameter&& src);
const Parameter& operator= (const Parameter &);
const Parameter& operator= (Parameter &&);
};
/// </code>
/// OSLQuery methods
/// ----------------
OSLQuery ();
///< Construct an uninitialized OSLQuery. It will not hold any
/// information about a shader until `open()` is called.
OSLQuery (string_view shadername,
string_view searchpath = string_view()) {
string_view searchpath = string_view()) {
open (shadername, searchpath);
}
///< Construct an OSLQuery and open a compiled shader from a disk file.
/// The `shadername` may be either the name of the `.oso` file, or the
/// name of the shader. The optional `searchpath` paramter gives a
/// colon-separated list of directories to search for compiled shaders.
OSLQuery (const ShaderGroup *group, int layernum) {
init (group, layernum);
}
///< Construct an OSLQuery and initialize it with an existing
/// `ShaderGroup` (which must have been built using the `ShadingSystem`
/// runtime API for OSL.
~OSLQuery ();
///< Clean up and destruct the `OSLQuery`.
/// Get info on the named shader with optional searcphath. Return
/// true for success, false if the shader could not be found or
/// opened properly.
bool open (string_view shadername,
string_view searchpath = string_view());
///< For an uninitialized `OSLQuery` object, initialize it with info on
/// the named shader with optional searcphath. Return true for success,
/// false if the shader could not be found or opened properly.
/// Get info on the shader from it's compiled bytecode. Return
/// true for success, false if the shader could not be found or
/// opened properly.
/// Meant to be called from an app which caches bytecodes from
bool open_bytecode (string_view buffer);
///< Get info on the shader from it's compiled bytecode (i.e., like the
/// contents of an `.oso` file, but in a string). Return `true` for
/// success, false if the shader could not be found or opened properly.
///
/// This is meant to be called from an app which caches bytecodes from
/// it's own side and wants to get shader info on runtime without
/// creating a temporary file.
bool open_bytecode (string_view buffer);
/// Meant to be called at runtime from an app with a full ShadingSystem,
bool init (const ShaderGroup *group, int layernum);
///< Meant to be called at runtime from an app with a full ShadingSystem,
/// fill out an OSLQuery structure for the given layer of the group.
/// This is much faster than using open() to read it from an oso file on
/// disk.
bool init (const ShaderGroup *group, int layernum);
/// Return the shader type: "surface", "displacement", "volume",
/// "light", or "shader" (for generic shaders).
const ustring shadertype (void) const { return m_shadertypename; }
///< Return the shader type: "surface", "displacement", "volume",
/// "light", or "shader" (for generic shaders).
/// Get the name of the shader.
///
const ustring shadername (void) const { return m_shadername; }
///< Get the name of the shader.
/// How many parameters does the shader have?
///
size_t nparams (void) const { return (int) m_params.size(); }
///< How many parameters does the shader have
/// Retrieve a parameter, either by index or by name. Return NULL if the
/// index is out of range, or if the named parameter is not found.
const Parameter *getparam (size_t i) const {
if (i >= nparams())
return NULL;
return &(m_params[i]);
}
const Parameter *getparam (const std::string &name) const {
for (size_t i = 0; i < nparams(); ++i)
if (m_params[i].name == name)
return &(m_params[i]);
return NULL;
}
const Parameter *getparam (ustring name) const {
for (size_t i = 0; i < nparams(); ++i)
if (m_params[i].name == name)
return &(m_params[i]);
return NULL;
}
const Parameter *getparam (size_t i) const;
const Parameter *getparam (const std::string &name) const;
const Parameter *getparam (ustring name) const;
///< Retrieve a parameter, either by index or by name. Return nullptr if
/// the index is out of range, or if the named parameter is not found.
/// Retrieve a reference to the metadata about the shader.
///
const std::vector<Parameter> &metadata (void) const { return m_meta; }
///< Retrieve a reference to the metadata about the shader.
/// Return error string, empty if there was no error, and reset the
///> Return error string, empty if there was no error, and reset the
/// error string.
std::string geterror (bool clear_error = true) {
std::string e = m_error;
@@ -157,24 +209,19 @@ public:
}
private:
ustring m_shadername; ///< Name of shader
ustring m_shadertypename; ///< Type of shader
mutable std::string m_error; ///< Error message
std::vector<Parameter> m_params; ///< Params to the shader
std::vector<Parameter> m_meta; ///< Meta-data about the shader
ustring m_shadername; //< Name of shader
ustring m_shadertypename; //< Type of shader
mutable std::string m_error; //< Error message
std::vector<Parameter> m_params; //< Params to the shader
std::vector<Parameter> m_meta; //< Meta-data about the shader
friend class pvt::OSOReaderQuery;
#if OIIO_VERSION >= 10803
/// Internal error reporting routine, with printf-like arguments.
// Internal error reporting routine, with printf-like arguments.
template<typename... Args>
inline void error (string_view fmt, const Args&... args) const {
append_error(OIIO::Strutil::format (fmt, args...));
}
#else
// Fallback for older OIIO
TINYFORMAT_WRAP_FORMAT (void, error, const,
std::ostringstream msg;, msg, append_error(msg.str());)
#endif
void append_error (const std::string& message) const {
if (m_error.size())
m_error += '\n';
@@ -183,4 +230,40 @@ private:
};
////////// Implementation
inline const OSLQuery::Parameter*
OSLQuery::getparam (size_t i) const
{
if (i >= nparams())
return nullptr;
return &(m_params[i]);
}
inline const OSLQuery::Parameter*
OSLQuery::getparam (const std::string &name) const
{
for (size_t i = 0; i < nparams(); ++i)
if (m_params[i].name == name)
return &(m_params[i]);
return nullptr;
}
inline const OSLQuery::Parameter*
OSLQuery::getparam (ustring name) const
{
for (size_t i = 0; i < nparams(); ++i)
if (m_params[i].name == name)
return &(m_params[i]);
return nullptr;
}
// more documentation
/// <inc oslinfo_source>
OSL_NAMESPACE_EXIT
+3 -1
View File
@@ -67,7 +67,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
OSL_LIBRARY_VERSION_PATCH, \
OSL_LIBRARY_VERSION_RELEASE_TYPE)
#define OSL_INTRO_STRING "OpenShadingLanguage " OSL_LIBRARY_VERSION_STRING
#define OSL_COPYRIGHT_STRING "(c) Copyright 2009-2017 Sony Pictures Imageworks, et al. All rights reserved."
#define OSL_COPYRIGHT_STRING "(c) Copyright 2009-2019 Sony Pictures Imageworks, et al. All rights reserved."
// Version numbers for the compiled shader format. The major number
@@ -97,5 +97,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#cmakedefine01 OSL_BUILD_CPP14
// OSL_BUILD_CPP17 will be 1 if this OSL was built using C++17
#cmakedefine01 OSL_BUILD_CPP17
// OSL_BUILD_CPP20 will be 1 if this OSL was built using C++20 or higher
#cmakedefine01 OSL_BUILD_CPP20
#endif /* OSLVERSION_H */
+22 -10
View File
@@ -82,7 +82,7 @@ public:
/// transformation at the given time. Return true if ok, false
/// on error.
virtual bool get_matrix (ShaderGlobals *sg, Matrix44 &result,
TransformationPtr xform, float time) = 0;
TransformationPtr xform, float time) { return false; }
/// Get the 4x4 matrix that transforms by the specified
/// transformation at the given time. Return true if ok, false on
@@ -97,7 +97,7 @@ public:
/// time value is given, also return false if the transformation may
/// be time-varying.
virtual bool get_matrix (ShaderGlobals *sg, Matrix44 &result,
TransformationPtr xform) = 0;
TransformationPtr xform) { return false; }
/// Get the 4x4 matrix that transforms by the specified
/// transformation. Return true if ok, false on error. Since no
@@ -112,7 +112,7 @@ public:
/// 'from' coordinate system to "common" space at the given time.
/// Returns true if ok, false if the named matrix is not known.
virtual bool get_matrix (ShaderGlobals *sg, Matrix44 &result,
ustring from, float time) = 0;
ustring from, float time) { return false; }
/// Get the 4x4 matrix that transforms points from "common" space to
/// the named 'to' coordinate system to at the given time. The
@@ -127,7 +127,7 @@ public:
/// transformation may be time-varying (as well as if it's not found
/// at all).
virtual bool get_matrix (ShaderGlobals *sg, Matrix44 &result,
ustring from) = 0;
ustring from) { return false; }
/// Get the 4x4 matrix that transforms points from "common" space to
/// the named 'to' coordinate system. Since there is no time value
@@ -183,20 +183,20 @@ public:
/// otherwise just fail by returning 'false'.
virtual bool get_attribute (ShaderGlobals *sg, bool derivatives,
ustring object, TypeDesc type, ustring name,
void *val ) = 0;
void *val) { return false; }
/// Similar to get_attribute(); this method will return the 'index'
/// element of an attribute array.
virtual bool get_array_attribute (ShaderGlobals *sg, bool derivatives,
ustring object, TypeDesc type,
ustring name, int index, void *val ) = 0;
ustring name, int index, void *val) { return false; }
/// Get the named user-data from the current object and write it into
/// 'val'. If derivatives is true, the derivatives should be written into val
/// as well. Return false if no user-data with the given name and type was
/// found.
virtual bool get_userdata (bool derivatives, ustring name, TypeDesc type,
ShaderGlobals *sg, void *val) = 0;
ShaderGlobals *sg, void *val) { return false; }
/// Given the name of a texture, return an opaque handle that can be
/// used with texture calls to avoid the name lookups.
@@ -244,8 +244,9 @@ public:
float dsdy, float dtdy, int nchannels,
float *result, float *dresultds, float *dresultdt,
ustring *errormessage);
// Deprecated version, with no errormessage parameter. This will
// DEPRECATED(1.8) version, with no errormessage parameter. This will
// eventually disappear.
OSL_DEPRECATED ("Deprecated since 1.8, use the version with an errormessage parameter.")
virtual bool texture (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
TextureOpt &options, ShaderGlobals *sg,
@@ -286,8 +287,9 @@ public:
float *result, float *dresultds,
float *dresultdt, float *dresultdr,
ustring *errormessage);
// Deprecated version, with no errormessage parameter. This will
// DEPRECATED(1.8) version, with no errormessage parameter. This will
// eventually disappear.
OSL_DEPRECATED ("Deprecated since 1.8, use the version with an errormessage parameter.")
virtual bool texture3d (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
TextureOpt &options, ShaderGlobals *sg,
@@ -325,8 +327,9 @@ public:
int nchannels, float *result,
float *dresultds, float *dresultdt,
ustring *errormessage);
// Deprecated version, with no errormessage parameter. This will
// DEPRECATED(1.8) version, with no errormessage parameter. This will
// eventually disappear.
OSL_DEPRECATED ("Deprecated since 1.8, use the version with an errormessage parameter.")
virtual bool environment (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
TextureOpt &options, ShaderGlobals *sg,
@@ -418,6 +421,15 @@ public:
/// Return a pointer to the texture system (if available).
virtual TextureSystem *texturesys () const;
/// Register a string with the renderer, so that the renderer can arrange
/// to make the string available in GPU memory as needed. Optionally specify
/// a variable name to associate with the string value.
virtual uint64_t register_string (const std::string& str,
const std::string& var_name)
{
return 0;
}
/// Options we use for noise calls.
struct NoiseOpt {
int anisotropic;
+21
View File
@@ -145,4 +145,25 @@ struct ShaderGlobals {
};
/// Enum giving values that can be 'or'-ed together to make a bitmask
/// of which "global" variables are needed or written to by the shader.
enum class SGBits {
None = 0,
P = 1 << 0,
I = 1 << 1,
N = 1 << 2,
Ng = 1 << 3,
u = 1 << 4,
v = 1 << 5,
dPdu = 1 << 6,
dPdv = 1 << 7,
time = 1 << 8,
dtime = 1 << 9,
dPdtime = 1 << 10,
Ps = 1 << 11,
Ci = 1 << 12,
last
};
OSL_NAMESPACE_EXIT
+146
View File
@@ -0,0 +1,146 @@
/*
Copyright (c) 2009-2018 Sony Pictures Imageworks Inc., et al.
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Sony Pictures Imageworks nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// This file contains "declarations" for all the strings that might get used in
// JITed shader code or in renderer code. But the declaration itself is
// dependent on the STRDECL macro, which should be declared by the outer file
// prior to including this file. Thus, this list may be repurposed and included
// multiple times, with different STRDECL definitions.
#ifndef STRDECL
#error Do not include this file unless STRDECL is defined
#endif
STRDECL ("", _emptystring_)
STRDECL ("camera", camera)
STRDECL ("common", common)
STRDECL ("object", object)
STRDECL ("shader", shader)
STRDECL ("screen", screen)
STRDECL ("NDC", NDC)
STRDECL ("rgb", rgb)
STRDECL ("RGB", RGB)
STRDECL ("hsv", hsv)
STRDECL ("hsl", hsl)
STRDECL ("YIQ", YIQ)
STRDECL ("XYZ", XYZ)
STRDECL ("xyz", xyz)
STRDECL ("xyY", xyY)
STRDECL ("null", null)
STRDECL ("default", default_)
STRDECL ("label", label)
STRDECL ("sidedness", sidedness)
STRDECL ("front", front)
STRDECL ("back", back)
STRDECL ("both", both)
STRDECL ("P", P)
STRDECL ("I", I)
STRDECL ("N", N)
STRDECL ("Ng", Ng)
STRDECL ("dPdu", dPdu)
STRDECL ("dPdv", dPdv)
STRDECL ("u", u)
STRDECL ("v", v)
STRDECL ("Ps", Ps)
STRDECL ("time", time)
STRDECL ("dtime", dtime)
STRDECL ("dPdtime", dPdtime)
STRDECL ("Ci", Ci)
STRDECL ("width", width)
STRDECL ("swidth", swidth)
STRDECL ("twidth", twidth)
STRDECL ("rwidth", rwidth)
STRDECL ("blur", blur)
STRDECL ("sblur", sblur)
STRDECL ("tblur", tblur)
STRDECL ("rblur", rblur)
STRDECL ("wrap", wrap)
STRDECL ("swrap", swrap)
STRDECL ("twrap", twrap)
STRDECL ("rwrap", rwrap)
STRDECL ("black", black)
STRDECL ("clamp", clamp)
STRDECL ("periodic", periodic)
STRDECL ("mirror", mirror)
STRDECL ("firstchannel", firstchannel)
STRDECL ("fill", fill)
STRDECL ("alpha", alpha)
STRDECL ("errormessage", errormessage)
STRDECL ("interp", interp)
STRDECL ("closest", closest)
STRDECL ("linear", linear)
STRDECL ("cubic", cubic)
STRDECL ("smartcubic", smartcubic)
STRDECL ("perlin", perlin)
STRDECL ("uperlin", uperlin)
STRDECL ("noise", noise)
STRDECL ("snoise", snoise)
STRDECL ("cell", cell)
STRDECL ("cellnoise", cellnoise)
STRDECL ("pcellnoise", pcellnoise)
STRDECL ("hash", hash)
STRDECL ("hashnoise", hashnoise)
STRDECL ("phashnoise", phashnoise)
STRDECL ("pnoise", pnoise)
STRDECL ("psnoise", psnoise)
STRDECL ("genericnoise", genericnoise)
STRDECL ("genericpnoise", genericpnoise)
STRDECL ("gabor", gabor)
STRDECL ("gabornoise", gabornoise)
STRDECL ("gaborpnoise", gaborpnoise)
STRDECL ("simplex", simplex)
STRDECL ("usimplex", usimplex)
STRDECL ("simplexnoise", simplexnoise)
STRDECL ("usimplexnoise", usimplexnoise)
STRDECL ("anisotropic", anisotropic)
STRDECL ("direction", direction)
STRDECL ("do_filter", do_filter)
STRDECL ("bandwidth", bandwidth)
STRDECL ("impulses", impulses)
STRDECL ("dowhile", op_dowhile)
STRDECL ("for", op_for)
STRDECL ("while", op_while)
STRDECL ("exit", op_exit)
STRDECL ("subimage", subimage)
STRDECL ("subimagename", subimagename)
STRDECL ("missingcolor", missingcolor)
STRDECL ("missingalpha", missingalpha)
STRDECL ("end", end)
STRDECL ("useparam", useparam)
STRDECL ("!!!uninitialized!!!", uninitialized_string)
STRDECL ("unull", unull)
STRDECL ("raytype", raytype)
STRDECL ("color", color)
STRDECL ("point", point)
STRDECL ("vector", vector)
STRDECL ("normal", normal)
STRDECL ("matrix", matrix)
STRDECL ("unknown", unknown)
+19 -28
View File
@@ -43,10 +43,9 @@ class StructSpec;
/// Kinds of shaders
///
enum ShaderType {
ShadTypeUnknown=0, ShadTypeGeneric, ShadTypeSurface,
ShadTypeDisplacement, ShadTypeVolume, ShadTypeLight,
ShadTypeLast
enum class ShaderType {
Unknown=0, Generic, Surface, Displacement, Volume, Light,
Last
};
@@ -60,24 +59,6 @@ ShaderType shadertype_from_name (string_view name);
/// Uses of shaders
///
enum ShaderUse {
ShadUseSurface, ShadUseDisplacement,
ShadUseLast, ShadUseUnknown = ShadUseLast
};
/// Convert a ShaderUse to a human-readable name ("surface", etc.)
///
const char *shaderusename (ShaderUse s);
/// Convert a ShaderUse to a human-readable name ("surface", etc.)
///
ShaderUse shaderuse_from_name (string_view name);
/// Kinds of symbols
///
enum SymType {
@@ -476,7 +457,8 @@ public:
m_symtype(symtype),
m_has_derivs(false), m_const_initializer(false),
m_connected_down(false),
m_initialized(false), m_lockgeom(false), m_renderer_output(false),
m_initialized(false), m_lockgeom(false), m_allowconnect(true),
m_renderer_output(false), m_readonly(false),
m_valuesource(DefaultVal), m_free_data(false),
m_fieldid(-1), m_layer(-1),
m_scope(0), m_dataoffset(-1), m_initializers(0),
@@ -496,7 +478,8 @@ public:
// since by design we have made this structure hold no unique
// pointers and have no elements that aren't safe to memcpy, even
// though the compiler probably can't figure that out.
if (this != &a) memcpy (this, &a, sizeof(Symbol));
// Cast to char* to defeat gcc8 rejecting this.
if (this != &a) memcpy ((char *)this, (const char *)&a, sizeof(Symbol));
return *this;
}
@@ -686,6 +669,9 @@ public:
bool lockgeom () const { return m_lockgeom; }
void lockgeom (bool lock) { m_lockgeom = lock; }
bool allowconnect () const { return m_allowconnect; }
void allowconnect (bool val) { m_allowconnect = val; }
int arraylen () const { return m_typespec.arraylength(); }
void arraylen (int len) {
m_typespec.make_array(len);
@@ -695,25 +681,28 @@ public:
bool renderer_output () const { return m_renderer_output; }
void renderer_output (bool v) { m_renderer_output = v; }
bool readonly () const { return m_readonly; }
void readonly (bool v) { m_readonly = v; }
bool is_constant () const { return symtype() == SymTypeConst; }
bool is_temp () const { return symtype() == SymTypeTemp; }
// Retrieve the const float value (will ASSERT if not a const float!)
float get_float (int index = 0) {
float get_float (int index = 0) const {
ASSERT (data() && typespec().is_float_based());
return ((const float *)data())[index];
}
// Retrieve the const int value (will ASSERT if not a const int!)
int get_int (int index = 0) {
int get_int (int index = 0) const {
ASSERT (data() && typespec().is_int_based());
return ((const int *)data())[index];
}
// Retrieve the const string value (will ASSERT if not a const string!)
ustring get_string () {
ustring get_string (int index = 0) const {
ASSERT (data() && typespec().is_string());
return ((const ustring *)data())[0];
return ((const ustring *)data())[index];
}
/// Stream output
@@ -731,7 +720,9 @@ protected:
unsigned m_connected_down:1;///< Connected to a later/downtream layer
unsigned m_initialized:1; ///< If a param, has it been initialized?
unsigned m_lockgeom:1; ///< Is the param not overridden by geom?
unsigned m_allowconnect:1; ///< Is the param not overridden by geom?
unsigned m_renderer_output:1; ///< Is this sym a renderer output?
unsigned m_readonly:1; ///< read-only symbol
char m_valuesource; ///< Where did the value come from?
bool m_free_data; ///< Free m_data upon destruction?
short m_fieldid; ///< Struct field of this var (or -1)
+9
View File
@@ -18,6 +18,15 @@ if (BUILDSTATIC)
ADD_DEFINITIONS ( -DBUILD_STATIC=1 )
else ()
ADD_LIBRARY ( oslcomp SHARED ${liboslcomp_srcs} )
if (VERBOSE)
message(STATUS "Setting SOVERSION to: ${SOVERSION}")
endif ()
set_target_properties( oslcomp
PROPERTIES
VERSION ${OSL_VERSION_MAJOR}.${OSL_VERSION_MINOR}.${OSL_VERSION_PATCH}
SOVERSION ${SOVERSION} )
endif ()
TARGET_LINK_LIBRARIES ( oslcomp ${OPENIMAGEIO_LIBRARIES} ${ILMBASE_LIBRARIES}
+222 -41
View File
@@ -26,10 +26,14 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <algorithm>
#include <vector>
#include <string>
#include <sstream>
#include <functional>
#ifndef NDEBUG
#include <atomic>
#endif
#include "osl_pvt.h"
#include "oslcomp_pvt.h"
@@ -73,6 +77,21 @@ ScopeExit print_node_counts ([](){
ASTNode::ref
reverse (ASTNode::ref list)
{
ASTNode::ref new_list;
while (list) {
ASTNode::ref next = list->next();
list->m_next = new_list;
new_list = list;
list = next;
}
return new_list;
}
ASTNode::ASTNode (NodeType nodetype, OSLCompilerImpl *compiler)
: m_nodetype(nodetype), m_compiler(compiler),
m_sourcefile(compiler->filename()),
@@ -177,12 +196,7 @@ ASTNode::~ASTNode ()
void
ASTNode::error_impl (string_view msg) const
{
#if OIIO_VERSION >= 10803
m_compiler->error (sourcefile(), sourceline(), "%s", msg);
#else
// DEPRECATED -- delete when minimum OIIO is at least 1.8
m_compiler->error (sourcefile(), sourceline(), "%s", msg.c_str());
#endif
}
@@ -190,12 +204,23 @@ ASTNode::error_impl (string_view msg) const
void
ASTNode::warning_impl (string_view msg) const
{
#if OIIO_VERSION >= 10803
m_compiler->warning (sourcefile(), sourceline(), "%s", msg);
#else
// DEPRECATED -- delete when minimum OIIO is at least 1.8
m_compiler->warning (sourcefile(), sourceline(), "%s", msg.c_str());
#endif
}
void
ASTNode::info_impl (string_view msg) const
{
m_compiler->info (sourcefile(), sourceline(), "%s", msg);
}
void
ASTNode::message_impl (string_view msg) const
{
m_compiler->message (sourcefile(), sourceline(), "%s", msg);
}
@@ -243,6 +268,45 @@ ASTNode::type_c_str (const TypeSpec &type) const
void
ASTNode::list_to_vec (const ref &A, std::vector<ref> &vec)
{
vec.clear ();
for (ref node = A; node; node = node->next())
vec.push_back (node);
}
ASTNode::ref
ASTNode::vec_to_list (std::vector<ref> &vec)
{
if (vec.size()) {
for (size_t i = 0; i < vec.size()-1; ++i)
vec[i]->m_next = vec[i+1];
vec[vec.size()-1]->m_next = NULL;
return vec[0];
} else {
return ref();
}
}
std::string
ASTNode::list_to_types_string (const ASTNode *node)
{
std::ostringstream result;
for (int i = 0; node; node = node->nextptr(), ++i) {
if (i)
result << ", ";
result << node->typespec();
}
return result.str();
}
ASTshader_declaration::ASTshader_declaration (OSLCompilerImpl *comp,
int stype, ustring name, ASTNode *form,
ASTNode *stmts, ASTNode *meta)
@@ -254,11 +318,11 @@ ASTshader_declaration::ASTshader_declaration (OSLCompilerImpl *comp,
ASSERT (arg->nodetype() == variable_declaration_node);
ASTvariable_declaration *v = (ASTvariable_declaration *)arg;
if (! v->init())
v->error ("shader parameter '%s' MUST have a default initializer",
v->name().c_str());
v->error ("shader parameter '%s' requires a default initializer",
v->name());
if (v->is_output() && v->typespec().is_unsized_array())
v->error ("shader output parameter '%s' can't be unsized array",
v->name().c_str());
v->name());
}
}
@@ -296,29 +360,31 @@ ASTshader_declaration::shadertypename () const
ASTfunction_declaration::ASTfunction_declaration (OSLCompilerImpl *comp,
TypeSpec type, ustring name,
ASTNode *form, ASTNode *stmts, ASTNode *meta)
ASTNode *form, ASTNode *stmts, ASTNode *meta,
int sourceline_start)
: ASTNode (function_declaration_node, comp, 0, meta, form, stmts),
m_name(name), m_sym(NULL), m_is_builtin(false)
{
m_typespec = type;
Symbol *f = comp->symtab().clash (name);
if (f && f->symtype() != SymTypeFunction) {
error ("\"%s\" already declared in this scope as a ", name.c_str(),
f->typespec().string().c_str());
// Some trickery -- the compiler's idea of the "current" source line
// is the END of the function body, so if a hint was passed about the
// start of the declaration, substitute that.
if (sourceline_start >= 0)
m_sourceline = sourceline_start;
if (Strutil::starts_with (name, "___"))
error ("\"%s\" : sorry, can't start with three underscores", name);
// Get a pointer to the first of the existing symbols of that name.
Symbol *existing_syms = comp->symtab().clash (name);
if (existing_syms && existing_syms->symtype() != SymTypeFunction) {
error ("\"%s\" already declared in this scope as a %s",
name, existing_syms->typespec());
// FIXME -- print the file and line of the other definition
f = NULL;
existing_syms = NULL;
}
// FIXME -- allow multiple function declarations, but only if they
// aren't the same polymorphic type.
if (name[0] == '_' && name[1] == '_' && name[2] == '_') {
error ("\"%s\" : sorry, can't start with three underscores",
name.c_str());
}
m_sym = new FunctionSymbol (name, type, this);
func()->nextpoly ((FunctionSymbol *)f);
// Build up the argument signature for this declared function
m_typespec = type;
std::string argcodes = oslcompiler->code_from_type (m_typespec);
for (ASTNode *arg = form; arg; arg = arg->nextptr()) {
const TypeSpec &t (arg->typespec());
@@ -333,6 +399,44 @@ ASTfunction_declaration::ASTfunction_declaration (OSLCompilerImpl *comp,
v->error ("function parameter '%s' may not have a default initializer.",
v->name().c_str());
}
// Allow multiple function declarations, but only if they aren't the
// same polymorphic type in the same scope.
if (stmts) {
std::string err;
int current_scope = oslcompiler->symtab().scopeid();
for (FunctionSymbol *f = static_cast<FunctionSymbol *>(existing_syms);
f; f = f->nextpoly()) {
if (f->scope() == current_scope && f->argcodes() == argcodes) {
// If the argcodes match, only one should have statements.
// If there is no ASTNode for the poly, must be a builtin, and
// has 'implicit' statements.
auto other = static_cast<ASTfunction_declaration*>(f->node());
if (!other || (other->statements() || other->is_builtin())) {
if (err.empty()) {
err = Strutil::format("Function '%s %s (%s)' redefined "
"in the same scope\n"
" Previous definitions:", type,
name, list_to_types_string(form));
}
err += "\n ";
if (other) {
err += Strutil::format("%s:%d",
OIIO::Filesystem::filename(other->sourcefile().string()),
other->sourceline());
} else
err += "built-in";
}
}
}
if (!err.empty())
warning ("%s", err);
}
m_sym = new FunctionSymbol (name, type, this);
func()->nextpoly ((FunctionSymbol *)existing_syms);
func()->argcodes (ustring (argcodes));
oslcompiler->symtab().insert (m_sym);
@@ -404,12 +508,25 @@ ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
const TypeSpec &type,
ustring name, ASTNode *init,
bool isparam, bool ismeta,
bool isoutput, bool initlist)
bool isoutput, bool initlist,
int sourceline_start)
: ASTNode (variable_declaration_node, comp, 0, init, NULL /* meta */),
m_name(name), m_sym(NULL),
m_isparam(isparam), m_isoutput(isoutput), m_ismetadata(ismeta),
m_initlist(initlist)
{
// Some trickery -- the compiler's idea of the "current" source line
// is the END of the declaration, so if a hint was passed about the
// start of the declaration, substitute that.
if (sourceline_start >= 0)
m_sourceline = sourceline_start;
if (m_initlist && init) {
// Typecheck the init list early.
ASSERT (init->nodetype() == compound_initializer_node);
static_cast<ASTcompound_initializer*>(init)->typecheck(type);
}
m_typespec = type;
Symbol *f = comp->symtab().clash (name);
if (f && ! m_ismetadata) {
@@ -421,14 +538,13 @@ ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
}
if (f->scope() == 0 && f->symtype() == SymTypeFunction && isparam) {
// special case: only a warning for param to mask global function
warning ("%s", e.c_str());
warning ("%s", e);
} else {
error ("%s", e.c_str());
error ("%s", e);
}
}
if (name[0] == '_' && name[1] == '_' && name[2] == '_') {
error ("\"%s\" : sorry, can't start with three underscores",
name.c_str());
if (OIIO::Strutil::starts_with (name, "___")) {
error ("\"%s\" : sorry, can't start with three underscores", name);
}
SymType symtype = isparam ? (isoutput ? SymTypeOutputParam : SymTypeParam)
: SymTypeLocal;
@@ -520,6 +636,14 @@ ASTvariable_ref::print (std::ostream &out, int indentlevel) const
ASTpreincdec::ASTpreincdec (OSLCompilerImpl *comp, int op, ASTNode *expr)
: ASTNode (preincdec_node, comp, op, expr)
{
check_symbol_writeability (expr);
}
const char *
ASTpreincdec::childname (size_t i) const
{
@@ -529,6 +653,14 @@ ASTpreincdec::childname (size_t i) const
ASTpostincdec::ASTpostincdec (OSLCompilerImpl *comp, int op, ASTNode *expr)
: ASTNode (postincdec_node, comp, op, expr)
{
check_symbol_writeability (expr);
}
const char *
ASTpostincdec::childname (size_t i) const
{
@@ -620,6 +752,8 @@ ASTstructselect::find_fieldsym (int &structid, int &fieldid)
{
if (! lvalue()->typespec().is_structure() &&
! lvalue()->typespec().is_structure_array()) {
error ("type '%s' does not have a member '%s'",
type_c_str(lvalue()->typespec()), m_field);
return NULL;
}
@@ -725,6 +859,18 @@ ASTconditional_statement::childname (size_t i) const
ASTloop_statement::ASTloop_statement (OSLCompilerImpl *comp, LoopType looptype,
ASTNode *init, ASTNode *cond,
ASTNode *iter, ASTNode *stmt)
: ASTNode (loop_statement_node, comp, looptype, init, cond, iter, stmt)
{
// Handle empty comparison, for(;;), is same as for(;1;)
if (!cond)
m_children[1] = new ASTliteral(comp, 1);
}
const char *
ASTloop_statement::childname (size_t i) const
{
@@ -778,7 +924,8 @@ ASTreturn_statement::childname (size_t i) const
ASTcompound_initializer::ASTcompound_initializer (OSLCompilerImpl *comp,
ASTNode *exprlist)
: ASTNode (compound_initializer_node, comp, Nothing, exprlist)
: ASTtype_constructor (compound_initializer_node, comp, TypeSpec(), exprlist),
m_ctor(false)
{
}
@@ -787,7 +934,39 @@ ASTcompound_initializer::ASTcompound_initializer (OSLCompilerImpl *comp,
const char *
ASTcompound_initializer::childname (size_t i) const
{
return "expression_list";
return canconstruct() ? "args" : "expression_list";
}
bool
ASTNode::check_symbol_writeability (ASTNode *var)
{
if (var->nodetype() == index_node)
return check_symbol_writeability (static_cast<ASTindex*>(var)->lvalue().get());
if (var->nodetype() == structselect_node)
return check_symbol_writeability (static_cast<ASTstructselect*>(var)->lvalue().get());
Symbol *dest = nullptr;
if (var->nodetype() == variable_ref_node)
dest = static_cast<ASTvariable_ref*>(var)->sym();
else if (var->nodetype() == variable_declaration_node)
dest = static_cast<ASTvariable_declaration*>(var)->sym();
if (dest) {
if (dest->readonly()) {
warning ("cannot write to non-output parameter \"%s\"", dest->name());
// Note: Consider it only a warning to write to a non-output
// parameter. Users who want it to be a hard error can use
// -Werror. Writing to any other readonly symbols is a full
// error.
return false;
}
} else {
// std::cout << "Don't know how to check_symbol_writeability "
// << var->nodetypename() << "\n";
}
return true;
}
@@ -801,6 +980,8 @@ ASTassign_expression::ASTassign_expression (OSLCompilerImpl *comp, ASTNode *var,
m_op = Assign;
m_children[1] = new ASTbinary_expression (comp, op, var, expr);
}
check_symbol_writeability (var);
}
@@ -1015,14 +1196,14 @@ ASTtype_constructor::childname (size_t i) const
ASTfunction_call::ASTfunction_call (OSLCompilerImpl *comp, ustring name,
ASTNode *args, FunctionSymbol *funcsym)
: ASTNode (function_call_node, comp, 0, args), m_name(name),
m_sym(funcsym ? funcsym : comp->symtab().find (name)), // Look it up.
m_poly(funcsym), // Default - resolved symbol or null
m_argread(~1), // Default - all args are read except the first
m_argwrite(1), // Default - first arg only is written by the op
m_argtakesderivs(0) // Default - doesn't take derivs
{
// If we weren't passed a function symbol directly, look it up.
m_sym = funcsym ? funcsym : comp->symtab().find (name);
if (! m_sym) {
error ("function '%s' was not declared in this scope", name.c_str());
error ("function '%s' was not declared in this scope", name);
// FIXME -- would be fun to troll through the symtab and try to
// find the things that almost matched and offer suggestions.
return;
+96 -81
View File
@@ -172,6 +172,9 @@ public:
return B;
}
/// Reverse the order of the list.
friend ASTNode::ref reverse (ASTNode::ref list);
/// What source file was this parse node created from?
///
ustring sourcefile () const { return m_sourcefile; }
@@ -186,11 +189,7 @@ public:
void error (string_view format, const Args&... args) const
{
DASSERT (format.size());
#if OIIO_VERSION >= 10803
error_impl (OIIO::Strutil::format (format, args...));
#else /* DEPRECATE when OIIO minimum is at least 1.8 */
error_impl (OIIO::Strutil::format (format.c_str(), args...));
#endif
}
/// Warning reporting
@@ -198,11 +197,23 @@ public:
void warning (string_view format, const Args&... args) const
{
DASSERT (format.size());
#if OIIO_VERSION >= 10803
warning_impl (OIIO::Strutil::format (format, args...));
#else /* DEPRECATE when OIIO minimum is at least 1.8 */
warning_impl (OIIO::Strutil::format (format.c_str(), args...));
#endif
}
/// info reporting
template<typename... Args>
void info (string_view format, const Args&... args) const
{
DASSERT (format.size());
info_impl (OIIO::Strutil::format (format, args...));
}
/// message reporting
template<typename... Args>
void message (string_view format, const Args&... args) const
{
DASSERT (format.size());
message_impl (OIIO::Strutil::format (format, args...));
}
bool is_lvalue () const { return m_is_lvalue; }
@@ -248,24 +259,15 @@ protected:
/// Flatten a list of nodes (headed by A) into a vector of node refs
/// (vec).
static void list_to_vec (const ref &A, std::vector<ref> &vec) {
vec.clear ();
for (ref node = A; node; node = node->next())
vec.push_back (node);
}
static void list_to_vec (const ref &A, std::vector<ref> &vec);
/// Turn a vector of node refs into a list of nodes, returning its
/// head.
static ref vec_to_list (std::vector<ref> &vec) {
if (vec.size()) {
for (size_t i = 0; i < vec.size()-1; ++i)
vec[i]->m_next = vec[i+1];
vec[vec.size()-1]->m_next = NULL;
return vec[0];
} else {
return ref();
}
}
static ref vec_to_list (std::vector<ref> &vec);
/// Generate a comma-separated string of data types of the list headed
/// by node (for example, "float, int, string").
static std::string list_to_types_string (const ASTNode *node);
/// Return the number of child nodes.
///
@@ -301,7 +303,8 @@ protected:
/// Type check a list (whose head is given by 'arg' against the list
/// of expected types given in encoded form by 'formals'.
bool check_arglist (const char *funcname, ref arg,
const char *formals, bool coerce=false);
const char *formals, bool coerce=false,
bool bind = true);
/// Follow a list of nodes, generating code for each in turn, and return
/// the Symbol* for the last thing generated.
@@ -347,25 +350,28 @@ protected:
bool copywholearrays, int intindex,
bool paraminit);
// Helper: type check an initializer list -- either a single item to
// a scalar, or a list to an array.
void typecheck_initlist (ref init, TypeSpec type, string_view name);
// Helper: generate code for an initializer list -- either a single
// item to a scalar, or a list to an array.
void codegen_initlist (ref init, TypeSpec type, Symbol *sym);
// Special type checking for structure member initializers.
// It's in the ASTNode base class because it's used from mutiple
// subclasses.
TypeSpec typecheck_struct_initializers (ref init, TypeSpec type,
string_view name);
// Special code generation for structure initializers.
// It's in the ASTNode base class because it's used from mutiple
// subclasses.
Symbol *codegen_struct_initializers (ref init, Symbol *sym,
bool is_constructor=false);
bool is_constructor=false,
Symbol *arrayindex = nullptr);
// Codegen an array assignemnt: lval[index] = src
// If no index is provided the constant i is used.
// Will return either src or a temporary that was codegened.
Symbol*
codegen_aassign (TypeSpec elemtype, Symbol *src, Symbol *lval,
Symbol* index, int i = 0);
// Check whether the node's symbol destination is ok to write. Return
// true if ok, return false and issue error or warning if not. (Used to
// check for writing to read-only variables like non-output parameters.)
bool check_symbol_writeability (ASTNode *var);
// Helper for param_default_literals: generate the string that gives
// the initialization of the literal value (and/or the default, if
@@ -376,6 +382,8 @@ protected:
void error_impl (string_view msg) const;
void warning_impl (string_view msg) const;
void info_impl (string_view msg) const;
void message_impl (string_view msg) const;
protected:
NodeType m_nodetype; ///< Type of node this is
@@ -420,7 +428,8 @@ class ASTfunction_declaration : public ASTNode
{
public:
ASTfunction_declaration (OSLCompilerImpl *comp, TypeSpec type, ustring name,
ASTNode *form, ASTNode *stmts, ASTNode *meta=NULL);
ASTNode *form, ASTNode *stmts, ASTNode *meta,
int sourceline_start=-1);
const char *nodetypename () const { return "function_declaration"; }
const char *childname (size_t i) const;
void print (std::ostream &out, int indentlevel=0) const;
@@ -449,9 +458,9 @@ class ASTvariable_declaration : public ASTNode
{
public:
ASTvariable_declaration (OSLCompilerImpl *comp, const TypeSpec &type,
ustring name, ASTNode *init, bool isparam=false,
bool ismeta=false, bool isoutput=false,
bool initlist=false);
ustring name, ASTNode *init, bool isparam,
bool ismeta, bool isoutput,
bool initlist, int sourceline_start=-1);
const char *nodetypename () const;
const char *childname (size_t i) const;
void print (std::ostream &out, int indentlevel=0) const;
@@ -522,9 +531,7 @@ private:
class ASTpreincdec : public ASTNode
{
public:
ASTpreincdec (OSLCompilerImpl *comp, int op, ASTNode *expr)
: ASTNode (preincdec_node, comp, op, expr)
{ }
ASTpreincdec (OSLCompilerImpl *comp, int op, ASTNode *expr);
const char *nodetypename () const { return m_op==Incr ? "preincrement" : "predecrement"; }
const char *childname (size_t i) const;
TypeSpec typecheck (TypeSpec expected);
@@ -538,9 +545,7 @@ public:
class ASTpostincdec : public ASTNode
{
public:
ASTpostincdec (OSLCompilerImpl *comp, int op, ASTNode *expr)
: ASTNode (postincdec_node, comp, op, expr)
{ }
ASTpostincdec (OSLCompilerImpl *comp, int op, ASTNode *expr);
const char *nodetypename () const { return m_op==Incr ? "postincrement" : "postdecrement"; }
const char *childname (size_t i) const;
TypeSpec typecheck (TypeSpec expected);
@@ -650,9 +655,7 @@ public:
};
ASTloop_statement (OSLCompilerImpl *comp, LoopType looptype, ASTNode *init,
ASTNode *cond, ASTNode *iter, ASTNode *stmt)
: ASTNode (loop_statement_node, comp, looptype, init, cond, iter, stmt)
{ }
ASTNode *cond, ASTNode *iter, ASTNode *stmt);
const char *nodetypename () const { return "loop_statement"; }
const char *childname (size_t i) const;
@@ -705,8 +708,41 @@ public:
class ASTcompound_initializer : public ASTNode
class ASTtype_constructor : public ASTNode
{
protected:
ASTtype_constructor (NodeType n, OSLCompilerImpl *c, TypeSpec t, ASTNode *a)
: ASTNode (n, c, Nothing, a) { m_typespec = t; }
public:
ASTtype_constructor (OSLCompilerImpl *comp, TypeSpec typespec,
ASTNode *args)
: ASTtype_constructor (type_constructor_node, comp, typespec, args) {}
const char *nodetypename () const { return "type_constructor"; }
const char *childname (size_t i) const;
Symbol *codegen (Symbol *dest = NULL);
ref args () const { return child (0); }
// Typecheck construction of expected against args()
// Optionally ignoring errors and binding any init-list arguments to the
// required type.
TypeSpec typecheck (TypeSpec expected, bool error, bool bind = true);
// Typecheck construction of m_typespec against args()
TypeSpec typecheck (TypeSpec expected) {
return typecheck (m_typespec, true, true);
}
};
class ASTcompound_initializer : public ASTtype_constructor
{
bool m_ctor;
TypeSpec typecheck (TypeSpec expected, unsigned mode);
public:
ASTcompound_initializer (OSLCompilerImpl *comp, ASTNode *exprlist);
const char *nodetypename () const { return "compound_initializer"; }
@@ -714,6 +750,16 @@ public:
Symbol *codegen (Symbol *dest = NULL);
ref initlist () const { return child (0); }
bool canconstruct() const { return m_ctor; }
void canconstruct(bool b) { m_ctor = b; }
TypeSpec typecheck (TypeSpec expected) {
return typecheck(expected, 0);
}
// Helper for typechecking an initlist or structure.
class TypeAdjuster;
};
@@ -838,26 +884,6 @@ public:
class ASTtype_constructor : public ASTNode
{
public:
ASTtype_constructor (OSLCompilerImpl *comp, TypeSpec typespec,
ASTNode *args)
: ASTNode (type_constructor_node, comp, 0, args)
{
m_typespec = typespec;
}
const char *nodetypename () const { return "type_constructor"; }
const char *childname (size_t i) const;
TypeSpec typecheck (TypeSpec expected);
Symbol *codegen (Symbol *dest = NULL);
ref args () const { return child (0); }
};
class ASTfunction_call : public ASTNode
{
public:
@@ -885,21 +911,10 @@ public:
/// Pointer to the ASTfunction_declaration node that defines the user
/// function, or NULL if it's not a user-defined function.
ASTfunction_declaration * user_function () const {
return (ASTfunction_declaration *) func()->node();
return func() ? (ASTfunction_declaration *) func()->node() : nullptr;
}
private:
/// Typecheck all polymorphic versions, return UNKNOWN if no match was
/// found, or a real type if there was a match. Also, upon matching,
/// re-jigger m_sym to point to the specific polymorphic match.
/// Allow arguments to be coerced (e.g., substituting a vector where
/// a point was expected, or a float where a color was expected) only
/// if coerceargs is true. For return values, allow spatial triples to
/// mutually match if 'equivreturn' is true, and allow any coercive
/// return type if 'expected' is TypeSpec() (i.e., unknown).
TypeSpec typecheck_all_poly (TypeSpec expected, bool coerceargs,
bool equivreturn);
/// Handle all the special cases for built-ins. This includes
/// irregular patterns of which args are read vs written, special
/// checks for printf- and texture-like, etc.
+183 -63
View File
@@ -461,10 +461,27 @@ ASTreturn_statement::codegen (Symbol *dest)
Symbol *
ASTcompound_initializer::codegen (Symbol *dest)
ASTcompound_initializer::codegen (Symbol *sym)
{
ASSERT(0 && "compound codegen");
return NULL;
if (canconstruct())
return ASTtype_constructor::codegen(sym);
if (m_typespec.is_structure_based()) {
if (!sym)
sym = m_compiler->make_temporary (m_typespec);
return codegen_struct_initializers (initlist(), sym, true /*is_constructor*/);
}
if (m_typespec.is_sized_array()) {
if (!sym)
sym = m_compiler->make_temporary (m_typespec);
codegen_initlist (initlist(), m_typespec, sym);
return sym;
}
error("Possible compiler bug: compound_initializer codegen does not "
"know how to handle type %s", typespec());
return nullptr;
}
@@ -648,7 +665,7 @@ ASTNode::one_default_literal (const Symbol *sym, ASTNode *init,
if (islit && lit->typespec().is_int())
out += Strutil::format ("%d", lit->intval());
else if (islit && lit->typespec().is_float())
out += Strutil::format ("%.8g", lit->floatval());
out += Strutil::format ("%.9g", lit->floatval());
else {
out += "0"; // FIXME?
completed = false;
@@ -656,12 +673,14 @@ ASTNode::one_default_literal (const Symbol *sym, ASTNode *init,
} else if (type.is_triple()) {
if (islit && lit->typespec().is_int()) {
float f = lit->intval();
out += Strutil::format ("%.8g%s%.8g%s%.8g", f, sep, f, sep, f);
out += Strutil::format ("%.9g%s%.9g%s%.9g", f, sep, f, sep, f);
} else if (islit && lit->typespec().is_float()) {
float f = lit->floatval();
out += Strutil::format ("%.8g%s%.8g%s%.8g", f, sep, f, sep, f);
out += Strutil::format ("%.9g%s%.9g%s%.9g", f, sep, f, sep, f);
} else if (init && init->typespec() == type &&
init->nodetype() == ASTNode::type_constructor_node) {
(init->nodetype() == ASTNode::type_constructor_node ||
(init->nodetype() == ASTNode::compound_initializer_node &&
static_cast<ASTcompound_initializer*>(init)->canconstruct()))) {
ASTtype_constructor *ctr = (ASTtype_constructor *) init;
ASTNode::ref val = ctr->args();
float f[3];
@@ -686,9 +705,9 @@ ASTNode::one_default_literal (const Symbol *sym, ASTNode *init,
}
}
if (nargs == 1)
out += Strutil::format ("%.8g%s%.8g%s%.8g", f[0], sep, f[0], sep, f[0]);
out += Strutil::format ("%.9g%s%.9g%s%.9g", f[0], sep, f[0], sep, f[0]);
else
out += Strutil::format ("%.8g%s%.8g%s%.8g", f[0], sep, f[1], sep, f[2]);
out += Strutil::format ("%.9g%s%.9g%s%.9g", f[0], sep, f[1], sep, f[2]);
} else {
out += Strutil::format ("0%s0%s0", sep, sep);
completed = false;
@@ -697,12 +716,12 @@ ASTNode::one_default_literal (const Symbol *sym, ASTNode *init,
if (islit && lit->typespec().is_int()) {
float f = lit->intval();
for (int c = 0; c < 16; ++c)
out += Strutil::format ("%.8g%s", (c/4)==(c%4) ? f : 0.0f,
out += Strutil::format ("%.9g%s", (c/4)==(c%4) ? f : 0.0f,
c<15 ? sep.c_str() : "");
} else if (islit && lit->typespec().is_float()) {
float f = lit->floatval();
for (int c = 0; c < 16; ++c)
out += Strutil::format ("%.8g%s", (c/4)==(c%4) ? f : 0.0f,
out += Strutil::format ("%.9g%s", (c/4)==(c%4) ? f : 0.0f,
c<15 ? sep.c_str() : "");
} else if (init && init->typespec() == type &&
init->nodetype() == ASTNode::type_constructor_node) {
@@ -730,11 +749,11 @@ ASTNode::one_default_literal (const Symbol *sym, ASTNode *init,
}
if (nargs == 1) {
for (int c = 0; c < 16; ++c)
out += Strutil::format ("%.8g%s", (c/4)==(c%4) ? f[0] : 0.0f,
out += Strutil::format ("%.9g%s", (c/4)==(c%4) ? f[0] : 0.0f,
c<15 ? sep.c_str() : "");
} else {
for (int c = 0; c < 16; ++c)
out += Strutil::format ("%.8g%s", f[c], c<15 ? sep.c_str() : "");
out += Strutil::format ("%.9g%s", f[c], c<15 ? sep.c_str() : "");
}
} else {
for (int c = 0; c < 16; ++c)
@@ -786,7 +805,9 @@ ASTvariable_declaration::param_default_literals (const Symbol *sym,
bool compound = (init && init->nodetype() == compound_initializer_node);
if (compound) {
init = ((ASTcompound_initializer *)init)->initlist().get();
compound = !static_cast<ASTcompound_initializer*>(init)->canconstruct();
if (compound)
init = ((ASTcompound_initializer *)init)->initlist().get();
}
bool completed = true; // have we output the full initialization?
@@ -823,13 +844,61 @@ ASTvariable_declaration::codegen_initializer (ref init, Symbol *sym)
init = ((ASTcompound_initializer *)init.get())->initlist();
codegen_initlist (init, typespec(), sym);
} else {
if (init->nodetype() == compound_initializer_node)
init = ((ASTcompound_initializer *)init.get())->initlist();
if (init->nodetype() == compound_initializer_node) {
ASTcompound_initializer* cinit = static_cast<ASTcompound_initializer*>(init.get());
init = cinit->initlist();
if (cinit->canconstruct()) {
bool paraminit = (m_compiler->codegen_method() != m_compiler->main_method_name() &&
(m_sym->symtype() == SymTypeParam ||
m_sym->symtype() == SymTypeOutputParam));
if (paraminit) {
// For parameter initialization, don't really generate ops if it
// can be statically initialized.
m_compiler->codegen_method (sym->name());
sym->initbegin (m_compiler->next_op_label ());
}
Symbol* dest = cinit->codegen(sym);
if (dest != sym)
emitcode ("assign", sym, dest);
if (paraminit)
sym->initend (m_compiler->next_op_label ());
return;
}
}
codegen_initlist (init, m_typespec, m_sym);
}
}
Symbol*
ASTNode::codegen_aassign (TypeSpec elemtype, Symbol *src, Symbol *lval,
Symbol* ind, int i)
{
const TypeSpec& srctype = src->typespec();
if (! equivalent (elemtype, srctype)) {
// Allow floatarray[ind] = int or intarray[ind] = float, but otherwise
// A[ind] = x is only allowed if the type of x is equivalent to that of
// A's elements.
// You can't for example, do colorarray[ind] = int.
if (elemtype.is_closure() || !elemtype.is_scalarnum() ||
srctype.is_closure() || !srctype.is_scalarnum()) {
// Convert through a temp.
Symbol *tmp = m_compiler->make_temporary (elemtype);
emitcode ("assign", tmp, src);
src = tmp;
}
}
if (!ind)
ind = m_compiler->make_constant (i);
emitcode ("aassign", lval, ind, src);
return src;
}
void
ASTNode::codegen_initlist (ref init, TypeSpec type, Symbol *sym)
@@ -863,6 +932,12 @@ ASTNode::codegen_initlist (ref init, TypeSpec type, Symbol *sym)
}
if (paraminit) {
// Warn early about struct array paramters.
// Handling this will likely need changes to oso format.
if (type.is_structure_array()) {
error ("array of struct are not allowed as parameters");
return;
}
// For parameter initialization, don't really generate ops if it
// can be statically initialized.
m_compiler->codegen_method (sym->name());
@@ -914,10 +989,39 @@ ASTNode::codegen_initlist (ref init, TypeSpec type, Symbol *sym)
return;
}
}
else if (type.is_structure_array()) {
for (int i = 0; init && i < type.arraylength(); ++i) {
ASTNode* expr = init.get();
bool ctor = false;
Symbol* dest = sym;
switch (expr->nodetype()) {
case function_call_node: {
ASTfunction_call* fcall = static_cast<ASTfunction_call*>(expr);
if ((ctor = fcall->is_struct_ctr())) {
expr = fcall->args().get();
ASSERT (expr != nullptr);
}
}
break;
case compound_initializer_node:
ctor = static_cast<ASTcompound_initializer*>(expr)->canconstruct();
break;
default:
break;
}
codegen_struct_initializers (expr, dest, ctor,
m_compiler->make_constant(i));
init = init->next();
}
if (paraminit)
sym->initend (m_compiler->next_op_label ());
return;
}
else if (init->nodetype() == compound_initializer_node)
init = ((ASTcompound_initializer *)init.get())->initlist();
// Loop over a list of initializers (it's just 1 if not an array)...
if (init->nodetype() == compound_initializer_node)
init = ((ASTcompound_initializer *)init.get())->initlist();
for (int i = 0; init; init = init->next(), ++i) {
if (sym->typespec().is_structure() &&
init->nodetype() == compound_initializer_node) {
@@ -931,17 +1035,8 @@ ASTNode::codegen_initlist (ref init, TypeSpec type, Symbol *sym)
if (dest != sym) {
if (sym->typespec().is_array()) {
// Array variable -- assign to the i-th element
TypeSpec elemtype = sym->typespec().elementtype();
if (! equivalent (elemtype, dest->typespec())) {
// We only allow A[ind] = x if the type of x is
// equivalent to that of A's elements. You can't,
// for example, do floatarray[ind] = int. So we
// convert through a temp.
Symbol *tmp = dest;
dest = m_compiler->make_temporary (elemtype);
emitcode ("assign", dest, tmp);
}
emitcode ("aassign", sym, m_compiler->make_constant(i), dest);
dest = codegen_aassign (sym->typespec().elementtype(), dest,
sym, nullptr, i);
} else {
// Non-array variable, just a simple assignment
emitcode ("assign", sym, dest);
@@ -959,7 +1054,7 @@ ASTNode::codegen_initlist (ref init, TypeSpec type, Symbol *sym)
Symbol *
ASTNode::codegen_struct_initializers (ref init, Symbol *sym,
bool is_constructor)
bool is_constructor, Symbol *arrayindex)
{
// If we're doing this initialization for shader params for their
// init ops, we need to take care to set the codegen method names
@@ -968,21 +1063,21 @@ ASTNode::codegen_struct_initializers (ref init, Symbol *sym,
(sym->symtype() == SymTypeParam ||
sym->symtype() == SymTypeOutputParam));
ASSERT (sym->typespec().is_structure());
ASSERT (sym->typespec().is_structure_based());
if (init->nodetype() != compound_initializer_node && !is_constructor) {
// Just one initializer, it's a whole struct of the right type.
Symbol *initsym = init->codegen (sym);
if (initsym != sym) {
StructSpec *structspec (sym->typespec().structspec());
codegen_assign_struct (structspec, ustring(sym->mangled()),
ustring(initsym->mangled()), NULL, true, 0,
paraminit);
ustring(initsym->mangled()), arrayindex,
true, 0, paraminit);
}
return sym;
}
// General case -- per-field initializers
if (init->nodetype() == compound_initializer_node) {
if (!is_constructor && init->nodetype() == compound_initializer_node) {
init = ((ASTcompound_initializer *)init.get())->initlist();
}
StructSpec *structspec (sym->typespec().structspec());
@@ -992,35 +1087,51 @@ ASTNode::codegen_struct_initializers (ref init, Symbol *sym,
ustring fieldname = ustring::format ("%s.%s", sym->mangled().c_str(),
field.name.c_str());
Symbol *fieldsym = m_compiler->symtab().find_exact (fieldname);
if (fieldsym->typespec().is_structure()) {
if (fieldsym->typespec().is_structure_based() &&
(init->nodetype() == type_constructor_node ||
init->nodetype() == compound_initializer_node)) {
bool ctor = init->nodetype() == type_constructor_node ? true :
static_cast<ASTcompound_initializer*>(init.get())->canconstruct();
// The field is itself a nested struct, so recurse
codegen_struct_initializers (init, fieldsym);
codegen_struct_initializers (init, fieldsym, ctor, arrayindex);
continue;
}
if (paraminit) {
if (paraminit && nodetype() == variable_declaration_node) {
// For parameter initialization, don't really generate ops if it
// can be statically initialized.
std::string out;
ASSERT (nodetype() == variable_declaration_node);
ASTvariable_declaration *v = (ASTvariable_declaration *)this;
if (v->param_default_literals (fieldsym, init.get(), out))
continue;
}
if (paraminit) {
// Delineate and remember the init ops for this field individually
m_compiler->codegen_method (fieldname);
fieldsym->initbegin (m_compiler->next_op_label ());
}
if (init->nodetype() == compound_initializer_node) {
if (init->nodetype() == compound_initializer_node &&
!((ASTcompound_initializer *)init.get())->canconstruct()) {
// Initialize the field with a compound initializer
codegen_initlist (((ASTcompound_initializer *)init.get())->initlist(),
field.type, fieldsym);
} else {
} else if (init->nodetype() == function_call_node &&
static_cast<ASTfunction_call*>(init.get())->is_struct_ctr()) {
codegen_struct_initializers (static_cast<ASTfunction_call*>(init.get())->args(),
fieldsym, true, arrayindex);
}
else {
// Initialize the field with a scalar initializer
Symbol *dest = init->codegen (fieldsym);
if (dest != fieldsym)
emitcode ("assign", fieldsym, dest);
if (dest != fieldsym) {
if (!arrayindex)
emitcode ("assign", fieldsym, dest);
else {
dest = codegen_aassign (fieldsym->typespec().elementtype(),
dest, fieldsym, arrayindex);
}
}
}
if (paraminit)
@@ -1177,19 +1288,8 @@ ASTindex::codegen_assign (Symbol *src, Symbol *ind,
emitcode ("compassign", temp, ind2, src);
emitcode ("aassign", lv, ind, temp);
}
else if (! equivalent (elemtype, src->typespec())) {
// Type conversion, e.g., colorarray[i] = float or
// floatarray[i] = int
// We only allow A[ind] = x if the type of x is equivalent
// to that of A's elements. You can't, for example, do
// floatarray[ind] = int. So we convert through a temp.
Symbol *tmp = src;
src = m_compiler->make_temporary (elemtype);
emitcode ("assign", src, tmp);
emitcode ("aassign", lv, ind, src);
} else {
// Simple Xarray[i] = X
emitcode ("aassign", lv, ind, src);
else {
src = codegen_aassign (elemtype, src, lv, ind);
}
} else if (lv->typespec().is_triple()) {
emitcode ("compassign", lv, ind, src);
@@ -1322,7 +1422,8 @@ ASTloop_statement::codegen (Symbol *)
codegen_list (init());
int condlabel = m_compiler->next_op_label ();
Symbol *condvar = cond()->codegen_int ();
Symbol *condvar = cond()->codegen_int (/*dest=*/ nullptr,
/*boolify=*/ true);
// Retroactively add the argument
size_t argstart = m_compiler->add_op_args (1, &condvar);
@@ -1605,11 +1706,19 @@ ASTtype_constructor::codegen (Symbol *dest)
// Doesn't fit the pattern, drop to the usual case...
}
// Special case: construct float(float_expr) -- just put it directly
// in the dest.
Symbol *argevaldest = nullptr;
if (dest && typespec().is_float() &&
nchildren() == 1 && child(0)->typespec().is_float()) {
argevaldest = dest;
}
std::vector<Symbol *> argdest;
argdest.push_back (dest);
int nargs = 0;
for (ref a = args(); a; a = a->next(), ++nargs) {
Symbol *argval = a->codegen();
Symbol *argval = a->codegen(argevaldest);
if (argval->typespec().is_int() && !typespec().is_int()) {
// Coerce to float if it's an int
if (a->nodetype() == literal_node) {
@@ -1625,9 +1734,16 @@ ASTtype_constructor::codegen (Symbol *dest)
}
argdest.push_back (argval);
}
if (nargs == 1)
if (nargs == 1 && argdest.size() == 2 && argdest[1] == dest) {
// Don't have to do anything, we already coaxed the one argument
// to show up in the requested destination. This can happen for
// foo = float(float_expr)
// to avoid the extra needless copy.
}
else if (nargs == 1) {
emitcode ("assign",
argdest.size(), (argdest.size())? &argdest[0]: NULL);
}
else
emitcode (typespec().string().c_str(),
argdest.size(), (argdest.size())? &argdest[0]: NULL);
@@ -1734,6 +1850,7 @@ ASTfunction_call::codegen (Symbol *dest)
// alias each of the fields
if (a->nodetype() == variable_ref_node ||
a->nodetype() == function_call_node ||
a->nodetype() == compound_initializer_node ||
a->nodetype() == binary_expression_node ||
a->nodetype() == unary_expression_node) {
// Passed a variable that is a struct ; make the struct
@@ -1873,10 +1990,13 @@ ASTfunction_call::codegen_arg (SymbolPtrVec &argdest, SymbolPtrVec &index1,
form->typespec().c_str());
}
}
argdest.push_back (thisarg);
index1.push_back (ind1);
index2.push_back (ind2);
index3.push_back (ind3);
if (thisarg) {
argdest.push_back (thisarg);
index1.push_back (ind1);
index2.push_back (ind2);
index3.push_back (ind3);
} else
arg->error("Invalid argument to function");
}
+122 -67
View File
@@ -95,12 +95,12 @@ OSLCompiler::compile (string_view filename,
bool
OSLCompiler::compile_buffer (string_view sourcecode,
std::string &osobuffer,
OSLCompiler::compile_buffer (string_view sourcecode, std::string &osobuffer,
const std::vector<std::string> &options,
string_view stdoslpath)
string_view stdoslpath, string_view filename)
{
return m_impl->compile_buffer (sourcecode, osobuffer, options, stdoslpath);
return m_impl->compile_buffer (sourcecode, osobuffer, options,
stdoslpath, filename);
}
@@ -116,7 +116,8 @@ OSLCompiler::output_filename () const
namespace pvt { // OSL::pvt
OSLCompilerImpl *oslcompiler = NULL;
OSLCompilerImpl *oslcompiler = nullptr;
static std::mutex oslcompiler_mutex;
static ustring op_for("for");
static ustring op_while("while");
@@ -129,7 +130,8 @@ OSLCompilerImpl::OSLCompilerImpl (ErrorHandler *errhandler)
m_err(false), m_symtab(*this),
m_current_typespec(TypeDesc::UNKNOWN), m_current_output(false),
m_verbose(false), m_quiet(false), m_debug(false),
m_preprocess_only(false), m_optimizelevel(1),
m_preprocess_only(false), m_err_on_warning(false),
m_optimizelevel(1),
m_next_temp(0), m_next_const(0),
m_osofile(NULL),
m_total_nesting(0), m_loop_nesting(0), m_derivsym(NULL),
@@ -204,8 +206,10 @@ OSLCompilerImpl::preprocess_buffer (const std::string &buffer,
context_type ctx (instring.begin(), instring.end(), filename.c_str());
// Turn on support of variadic macros, e.g. #define FOO(...) __VA_ARGS__
// Turn off whitespace insertion.
boost::wave::language_support lang = boost::wave::language_support (
ctx.get_language() | boost::wave::support_option_variadics);
(ctx.get_language() | boost::wave::support_option_variadics)
& ~boost::wave::language_support::support_option_insert_whitespace);
ctx.set_language (lang);
ctx.add_macro_definition (OIIO::Strutil::format("OSL_VERSION_MAJOR=%d",
@@ -309,7 +313,7 @@ OSLCompilerImpl::preprocess_buffer (const std::string &buffer,
new clang::DiagnosticsEngine(diagIDs, diagOptions, diagPrinter);
inst.setDiagnostics(diagEngine);
const std::shared_ptr<clang::TargetOptions> &targetopts =
const std::shared_ptr<clang::TargetOptions> targetopts =
std::make_shared<clang::TargetOptions>(inst.getTargetOpts());
targetopts->Triple = llvm::sys::getDefaultTargetTriple();
clang::TargetInfo *target =
@@ -319,16 +323,15 @@ OSLCompilerImpl::preprocess_buffer (const std::string &buffer,
inst.createFileManager();
inst.createSourceManager(inst.getFileManager());
#if OSL_LLVM_VERSION <= 35
clang::FrontendInputFile inputFile(mbuf.release(), clang::IK_None);
inst.InitializeSourceManager(inputFile);
#else
clang::SourceManager &sm = inst.getSourceManager();
sm.setMainFileID (sm.createFileID(std::move(mbuf), clang::SrcMgr::C_User));
#endif
inst.getPreprocessorOutputOpts().ShowCPP = 1;
inst.getPreprocessorOutputOpts().ShowMacros = 0;
inst.getPreprocessorOutputOpts().ShowComments = 0;
inst.getPreprocessorOutputOpts().ShowLineMarkers = 1;
inst.getPreprocessorOutputOpts().ShowMacroComments = 0;
inst.getPreprocessorOutputOpts().ShowIncludeDirectives = 0;
clang::HeaderSearchOptions &headerOpts = inst.getHeaderSearchOpts();
headerOpts.UseBuiltinIncludes = 0;
@@ -412,6 +415,8 @@ OSLCompilerImpl::read_compile_options (const std::vector<std::string> &options,
m_optimizelevel = 1;
} else if (options[i] == "-O2") {
m_optimizelevel = 2;
} else if (options[i] == "-Werror") {
m_err_on_warning = true;
} else if (options[i].c_str()[0] == '-' && options[i].size() > 2) {
// options meant for the preprocessor
if (options[i].c_str()[1] == 'D' || options[i].c_str()[1] == 'U')
@@ -429,10 +434,20 @@ OSLCompilerImpl::read_compile_options (const std::vector<std::string> &options,
static string_view
find_stdoslpath (const std::vector<std::string>& includepaths)
{
// first look in $OSLHOME/shaders
std::string OSLHOME = OIIO::Sysutil::getenv ("OSLHOME");
if (! OSLHOME.empty()) {
std::string path = OSLHOME + "/shaders";
// first look in $OSL_ROOT_DIR/shaders
std::string osl_root_dir = OIIO::Sysutil::getenv ("OSL_ROOT_DIR");
if (! osl_root_dir.empty()) {
std::string path = osl_root_dir + "/shaders";
if (OIIO::Filesystem::is_directory (path)) {
path = path + "/stdosl.h";
if (OIIO::Filesystem::exists (path))
return ustring(path);
}
}
// deprecated name: OSLHOME
osl_root_dir = OIIO::Sysutil::getenv ("OSLHOME");
if (! osl_root_dir.empty()) {
std::string path = osl_root_dir + "/shaders";
if (OIIO::Filesystem::is_directory (path)) {
path = path + "/stdosl.h";
if (OIIO::Filesystem::exists (path))
@@ -440,8 +455,8 @@ find_stdoslpath (const std::vector<std::string>& includepaths)
}
}
// If no OSLHOME, try looking wherever this program (the one running)
// lives, in a shaders or lib/osl/include directory.
// If not found in $OSL_ROOT_DIR, try looking wherever this program (the
// one running) lives, in a shaders or lib/osl/include directory.
std::string program = OIIO::Sysutil::this_program_path ();
if (program.size()) {
std::string path (program); // our program
@@ -521,6 +536,7 @@ OSLCompilerImpl::compile (string_view filename,
std::vector<std::string> includepaths;
m_cwd = OIIO::Filesystem::current_path();
m_main_filename = filename;
clear_filecontents_cache();
read_compile_options (options, defines, includepaths);
@@ -543,6 +559,9 @@ OSLCompilerImpl::compile (string_view filename,
} else if (m_preprocess_only) {
std::cout << preprocess_result;
} else {
// Thread safety with the lexer/parser
std::lock_guard<std::mutex> lock (oslcompiler_mutex);
oslcompiler = this;
bool parseerr = osl_parse_buffer (preprocess_result);
if (! parseerr) {
if (shader())
@@ -575,7 +594,7 @@ OSLCompilerImpl::compile (string_view filename,
OIIO::Filesystem::open (oso_output, m_output_filename);
if (! oso_output.good()) {
error (ustring(), 0, "Could not open \"%s\"",
m_output_filename.c_str());
m_output_filename);
return false;
}
ASSERT (m_osofile == NULL);
@@ -585,7 +604,7 @@ OSLCompilerImpl::compile (string_view filename,
ASSERT (m_osofile == NULL);
}
oslcompiler = NULL;
oslcompiler = nullptr;
}
return ! error_encountered();
@@ -597,9 +616,11 @@ bool
OSLCompilerImpl::compile_buffer (string_view sourcecode,
std::string &osobuffer,
const std::vector<std::string> &options,
string_view stdoslpath)
string_view stdoslpath,
string_view filename)
{
string_view filename ("<buffer>");
if (filename.empty())
filename = string_view("<buffer>");
std::vector<std::string> defines;
std::vector<std::string> includepaths;
@@ -607,6 +628,7 @@ OSLCompilerImpl::compile_buffer (string_view sourcecode,
m_cwd = OIIO::Filesystem::current_path();
m_main_filename = filename;
clear_filecontents_cache();
// Determine where the installed shader include directory is, and
// look for ../shaders/stdosl.h and force it to include.
@@ -623,6 +645,9 @@ OSLCompilerImpl::compile_buffer (string_view sourcecode,
} else if (m_preprocess_only) {
std::cout << preprocess_result;
} else {
// Thread safety with the lexer/parser
std::lock_guard<std::mutex> lock (oslcompiler_mutex);
oslcompiler = this;
bool parseerr = osl_parse_buffer (preprocess_result);
if (! parseerr) {
if (shader())
@@ -648,7 +673,8 @@ OSLCompilerImpl::compile_buffer (string_view sourcecode,
}
if (! error_encountered()) {
m_output_filename = "<buffer>";
if (m_output_filename.empty())
m_output_filename = default_output_filename ();
std::ostringstream oso_output;
oso_output.imbue (std::locale::classic()); // force C locale
@@ -660,7 +686,7 @@ OSLCompilerImpl::compile_buffer (string_view sourcecode,
ASSERT (m_osofile == NULL);
}
oslcompiler = NULL;
oslcompiler = nullptr;
}
return ! error_encountered();
@@ -671,6 +697,10 @@ OSLCompilerImpl::compile_buffer (string_view sourcecode,
struct GlobalTable {
const char *name;
TypeSpec type;
bool readonly;
GlobalTable (const char *name, TypeSpec type, bool readonly=true)
: name(name), type(type), readonly(readonly) {}
};
@@ -678,34 +708,24 @@ void
OSLCompilerImpl::initialize_globals ()
{
static GlobalTable globals[] = {
{ "P", TypeDesc::TypePoint },
{ "I", TypeDesc::TypeVector },
{ "N", TypeDesc::TypeNormal },
{ "P", TypeDesc::TypePoint, false },
{ "I", TypeDesc::TypeVector, false },
{ "N", TypeDesc::TypeNormal, false },
{ "Ng", TypeDesc::TypeNormal },
{ "u", TypeDesc::TypeFloat },
{ "v", TypeDesc::TypeFloat },
{ "dPdu", TypeDesc::TypeVector },
{ "dPdv", TypeDesc::TypeVector },
#if 0
// Light variables -- we don't seem to be on a route to support this
// kind of light shader, so comment these out for now.
{ "L", TypeDesc::TypeVector },
{ "Cl", TypeDesc::TypeColor },
{ "Ns", TypeDesc::TypeNormal },
{ "Pl", TypeDesc::TypePoint },
{ "Nl", TypeDesc::TypeNormal },
#endif
{ "Ps", TypeDesc::TypePoint },
{ "Ci", TypeSpec (TypeDesc::TypeColor, true) },
{ "Ci", TypeSpec (TypeDesc::TypeColor, true), false },
{ "time", TypeDesc::TypeFloat },
{ "dtime", TypeDesc::TypeFloat },
{ "dPdtime", TypeDesc::TypeVector },
{ NULL }
{ "dPdtime", TypeDesc::TypeVector }
};
for (int i = 0; globals[i].name; ++i) {
Symbol *s = new Symbol (ustring(globals[i].name), globals[i].type,
SymTypeGlobal);
for (auto& g : globals) {
Symbol *s = new Symbol (ustring(g.name), g.type, SymTypeGlobal);
s->readonly (g.readonly);
symtab().insert (s);
}
}
@@ -759,10 +779,10 @@ OSLCompilerImpl::write_oso_const_value (const ConstantSymbol *sym) const
oso ("%d%s", sym->intval(i), nelements>1 ? " " : "");
else if (elemtype == TypeDesc::FLOAT)
for (int i = 0; i < nelements; ++i)
oso ("%.8g%s", sym->floatval(i), nelements>1 ? " " : "");
oso ("%.9g%s", sym->floatval(i), nelements>1 ? " " : "");
else if (equivalent (elemtype, TypeDesc::TypeVector))
for (int i = 0; i < nelements; ++i)
oso ("%.8g %.8g %.8g%s", sym->vecval(i)[0], sym->vecval(i)[1],
oso ("%.9g %.9g %.9g%s", sym->vecval(i)[0], sym->vecval(i)[1],
sym->vecval(i)[2], nelements>1 ? " " : "");
else {
ASSERT (0 && "Don't know how to output this constant type");
@@ -942,7 +962,7 @@ OSLCompilerImpl::write_oso_file (const std::string &outfilename,
lastline = -1;
}
if (/*m_debug &&*/ op.sourcefile()) {
if (/*m_debug &&*/ !op.sourcefile().empty()) {
ustring file = op.sourcefile();
int line = op.sourceline();
if (file != lastfile || line != lastline)
@@ -975,7 +995,7 @@ OSLCompilerImpl::write_oso_file (const std::string &outfilename,
// %filename and %line document the source code file and line that
// contained code that generated this op. To avoid clutter, we
// only output these hints when they DIFFER from the previous op.
if (op.sourcefile()) {
if (!op.sourcefile().empty()) {
if (op.sourcefile() != lastfile) {
lastfile = op.sourcefile();
oso ("%c%%filename{\"%s\"}", firsthint ? '\t' : ' ', lastfile);
@@ -1004,11 +1024,7 @@ OSLCompilerImpl::write_oso_file (const std::string &outfilename,
// %argderivs documents which arguments have derivs taken of
// them by the op.
if (op.argtakesderivs_all()) {
#if OIIO_VERSION >= 10803
oso (" %%argderivs{");
#else
oso (" %cargderivs{", '%'); // trick to work with older OIIO
#endif
int any = 0;
for (int i = 0; i < op.nargs(); ++i)
if (op.argtakesderivs(i)) {
@@ -1032,29 +1048,70 @@ OSLCompilerImpl::write_oso_file (const std::string &outfilename,
std::string
void
OSLCompilerImpl::clear_filecontents_cache()
{
m_filecontents_map.clear();
m_last_sourcefile.clear();
m_last_filecontents = nullptr;
m_last_sourceline = 1; // note we call the first line "1" for users
m_last_sourceline_offset = 0;
}
string_view
OSLCompilerImpl::retrieve_source (ustring filename, int line)
{
// If we don't already have the file open, open it
if (filename != m_last_sourcefile) {
bool ok = OIIO::Filesystem::read_text_file (filename, m_filecontents);
if (ok) {
m_last_sourcefile = filename;
// If we don't have a valid "last", look it up in the cache.
if (filename != m_last_sourcefile || !m_last_filecontents) {
m_last_sourceline = 1;
m_last_sourceline_offset = 0;
auto found = m_filecontents_map.find (filename);
if (found == m_filecontents_map.end()) {
// If it wasn't in the cache, read the file and add it.
std::string contents;
bool ok = OIIO::Filesystem::read_text_file (filename, contents);
if (ok) {
m_last_sourcefile = filename;
m_filecontents_map[filename] = std::move(contents);
m_last_filecontents = &m_filecontents_map[filename];
} else {
m_last_sourcefile = ustring();
m_last_filecontents = nullptr;
return "<file not found>";
}
} else {
m_last_sourcefile = ustring();
return "<file not found>";
m_last_sourcefile = filename;
m_last_filecontents = &found->second;
}
}
// Now read lines up to and including the file we want.
OIIO::string_view s (m_filecontents);
OIIO::string_view s (*m_last_filecontents);
int orig_sourceline = line;
if (line >= m_last_sourceline) {
// Shortcut: the line we want is in the same file as the last read,
// and at least as far in the file. Start the search from where we
// left off last time.
s.remove_prefix (m_last_sourceline_offset);
line -= m_last_sourceline - 1;
} else {
// If we have to backtrack at all, backtrack to the file start.
m_last_sourceline_offset = 0;
m_last_sourceline = 1;
}
size_t offset = m_last_sourceline_offset;
for ( ; line > 1; --line) {
size_t p = s.find_first_of ('\n');
if (p == OIIO::string_view::npos)
return "<line not found>";
s.remove_prefix (p+1);
offset += p+1;
}
s = s.substr (0, s.find_first_of ('\n'));
m_last_sourceline_offset = offset;
m_last_sourceline = orig_sourceline;
return s;
}
@@ -1140,8 +1197,9 @@ OSLCompilerImpl::struct_field_pair (const StructSpec *structspec, int fieldnum,
/// Verify that the given symbol (written by the given op) is legal to
/// be written.
/// Verify that the given symbol (written by the given op) is legal to be
/// written. If writeable, it's writeable, We don't try to enforce
/// differences in policy per shader types.
void
OSLCompilerImpl::check_write_legality (const Opcode &op, int opnum,
const Symbol *sym)
@@ -1156,12 +1214,9 @@ OSLCompilerImpl::check_write_legality (const Opcode &op, int opnum,
if (sym->symtype() == SymTypeParam &&
(opnum < sym->initbegin() || opnum >= sym->initend())) {
error (op.sourcefile(), op.sourceline(),
"Cannot write to input parameter '%s' (op %d)",
sym->name().c_str(), opnum);
"cannot write to non-output parameter \"%s\"",
sym->name());
}
// FIXME -- check for writing to globals. But it's tricky, depends on
// what kind of shader we are.
}
+66 -24
View File
@@ -72,7 +72,8 @@ public:
bool compile_buffer (string_view sourcecode,
std::string &osobuffer,
const std::vector<std::string> &options,
string_view stdoslpath);
string_view stdoslpath,
string_view filename);
bool osl_parse_buffer (const std::string &preprocessed_buffer);
@@ -100,45 +101,69 @@ public:
/// Error reporting
template<typename... Args>
void error (string_view filename, int line,
void error (ustring filename, int line,
string_view format, const Args&... args) const
{
ASSERT (format.size());
#if OIIO_VERSION >= 10804
std::string msg = OIIO::Strutil::format (format, args...);
if (msg.size() && msg.back() == '\n') // trim extra newline
msg.pop_back();
if (filename.size())
m_errhandler->error ("%s:%d: error: %s", filename, line, msg);
else
m_errhandler->error ("error: %s", msg);
#else /* Deprecate when the OIIO minimum is 1.8 */
std::string msg = OIIO::Strutil::format (format.c_str(), args...);
if (filename.size())
m_errhandler->error ("%s:%d: error: %s", filename.c_str(), line, msg.c_str());
else
m_errhandler->error ("error: %s", msg.c_str());
#endif
m_err = true;
}
/// Warning reporting
template<typename... Args>
void warning (string_view filename, int line,
void warning (ustring filename, int line,
string_view format, const Args&... args) const
{
ASSERT (format.size());
#if OIIO_VERSION >= 10804
if (nowarn(filename, line))
return; // skip if the filename/line is on the nowarn list
std::string msg = OIIO::Strutil::format (format, args...);
if (msg.size() && msg.back() == '\n') // trim extra newline
msg.pop_back();
if (m_err_on_warning) {
error (filename, line, "%s", msg);
return;
}
if (filename.size())
m_errhandler->warning ("%s:%d: warning: %s", filename, line, msg);
else
m_errhandler->warning ("warning: %s", msg);
#else /* Deprecate when the OIIO minimum is 1.8 */
std::string msg = OIIO::Strutil::format (format.c_str(), args...);
}
/// Info reporting
template<typename... Args>
void info (ustring filename, int line,
string_view format, const Args&... args) const
{
ASSERT (format.size());
std::string msg = OIIO::Strutil::format (format, args...);
if (msg.size() && msg.back() == '\n') // trim extra newline
msg.pop_back();
if (filename.size())
m_errhandler->warning ("%s:%d: warning: %s", filename.c_str(), line, msg.c_str());
m_errhandler->info ("%s:%d: info: %s", filename, line, msg);
else
m_errhandler->warning ("warning: %s", msg.c_str());
#endif
m_errhandler->info ("info: %s", msg);
}
/// message reporting
template<typename... Args>
void message (ustring filename, int line,
string_view format, const Args&... args) const
{
ASSERT (format.size());
std::string msg = OIIO::Strutil::format (format, args...);
if (msg.size() && msg.back() == '\n') // trim extra newline
msg.pop_back();
if (filename.size())
m_errhandler->message ("%s:%d: %s", filename, line, msg);
else
m_errhandler->message ("%s", msg);
}
/// Have we hit an error?
@@ -357,6 +382,16 @@ public:
m_func_decls.emplace_back (f);
}
// Add a pragma nowarn for the following line
void pragma_nowarn () {
m_nowarn_lines.insert ({filename(), lineno()+1});
}
// Is the line amont
bool nowarn (ustring filename, int line) const {
return m_nowarn_lines.find({filename, line}) != m_nowarn_lines.end();
}
private:
void initialize_globals ();
void initialize_builtin_funcs ();
@@ -366,14 +401,10 @@ private:
void write_oso_symbol (const Symbol *sym);
void write_oso_metadata (const ASTNode *metanode) const;
#if OIIO_VERSION >= 10803
template<typename... Args>
inline void oso (string_view fmt, const Args&... args) const {
(*m_osofile) << OIIO::Strutil::format (fmt, args...);
}
#else
TINYFORMAT_WRAP_FORMAT (void, oso, const, , (*m_osofile), )
#endif
void track_variable_lifetimes () {
track_variable_lifetimes (m_ircode, m_opargs, symtab().allsyms());
@@ -423,7 +454,12 @@ private:
return NULL;
return static_cast<ASTshader_declaration *>(m_shader.get());
}
std::string retrieve_source (ustring filename, int line);
// Retrieve the particular line of a file.
string_view retrieve_source (ustring filename, int line);
// Clear internal caches that speed up retrieve_source().
void clear_filecontents_cache();
ustring m_filename; ///< Current file we're parsing
int m_lineno; ///< Current line we're parsing
@@ -441,6 +477,7 @@ private:
bool m_quiet; ///< Quiet mode
bool m_debug; ///< Debug mode
bool m_preprocess_only; ///< Preprocess only?
bool m_err_on_warning; ///< Treat warnings as errors?
int m_optimizelevel; ///< Optimization level
OpcodeVec m_ircode; ///< Generated IR code
SymbolPtrVec m_opargs; ///< Arguments for all instructions
@@ -448,8 +485,6 @@ private:
int m_next_const; ///< Next const symbol index
std::vector<ConstantSymbol *> m_const_syms; ///< All consts we've made
std::ostream *m_osofile; ///< Open .oso stream for output
std::string m_filecontents; ///< Contents of source file
ustring m_last_sourcefile;///< Last filename for retrieve_source
ustring m_codegenmethod; ///< Current method we're generating code for
std::stack<FunctionSymbol *> m_function_stack; ///< Stack of called funcs
int m_total_nesting; ///< total conditional nesting level (0 == none)
@@ -458,6 +493,13 @@ private:
Symbol *m_derivsym; ///< Pseudo-symbol to track deriv dependencies
int m_main_method_start; ///< Instruction where 'main' starts
bool m_declaring_shader_formals; ///< Are we declaring shader formals?
std::set<std::pair<ustring,int>> m_nowarn_lines; ///< Lines for 'nowarn'
typedef std::unordered_map<ustring,std::string,ustringHash> FCMap;
FCMap m_filecontents_map; ///< Contents of source files we've seen
ustring m_last_sourcefile;///< Last filename for retrieve_source
std::string* m_last_filecontents = nullptr; //< Last file contents
int m_last_sourceline;
size_t m_last_sourceline_offset;
};
+206 -89
View File
@@ -107,6 +107,7 @@ static std::stack<TypeSpec> typespec_stack; // just for function_declaration
%type <n> variable_declaration def_expressions def_expression
%type <n> initializer_opt initializer initializer_list_opt initializer_list
%type <n> compound_initializer init_expression_list init_expression
%type <n> init_expression_list_rev
%type <i> outputspec arrayspec simple_typename
%type <i> typespec typespec_or_shadertype
%type <n> statement_list statement scoped_statements local_declaration
@@ -170,7 +171,7 @@ global_declaration
shader_or_function_declaration
: typespec_or_shadertype IDENTIFIER
{
if ($1 == ShadTypeUnknown) {
if ($1 == (int)ShaderType::Unknown) {
// It's a function declaration, not a shader
oslcompiler->symtab().push (); // new scope
typespec_stack.push (oslcompiler->current_typespec());
@@ -178,7 +179,7 @@ shader_or_function_declaration
}
metadata_block_opt '('
{
if ($1 != ShadTypeUnknown)
if ($1 != (int)ShaderType::Unknown)
oslcompiler->declaring_shader_formals (true);
}
formal_params_opt ')'
@@ -187,18 +188,19 @@ shader_or_function_declaration
}
metadata_block_opt function_body_or_just_decl
{
if ($1 == ShadTypeUnknown) {
if ($1 == (int)ShaderType::Unknown) {
// Function declaration
oslcompiler->symtab().pop (); // restore scope
ASTfunction_declaration *f;
f = new ASTfunction_declaration (oslcompiler,
typespec_stack.top(),
ustring($2), $7 /*formals*/,
$11 /*statements*/);
$11 /*statements*/,
NULL /*metadata*/,
@2.first_line);
oslcompiler->remember_function_decl (f);
f->add_meta (concat($4, $10));
$$ = f;
$$->sourceline (@2.first_line);
typespec_stack.pop ();
} else {
// Shader declaration
@@ -232,12 +234,17 @@ formal_params
formal_param
: outputspec typespec IDENTIFIER initializer_opt metadata_block_opt
{
ASTvariable_declaration *var;
TypeSpec t = oslcompiler->current_typespec();
var = new ASTvariable_declaration (oslcompiler,
bool is_output = $1;
auto var = new ASTvariable_declaration (oslcompiler,
t, ustring($3), $4 /*init*/,
oslcompiler->declaring_shader_formals() /*isparam*/,
false /*ismeta*/, $1 /*isoutput*/);
false /*ismeta*/, is_output,
false /*instlist*/, @3.first_line);
if (! oslcompiler->declaring_shader_formals() && !is_output) {
// these are function formals, not shader formals,
var->sym()->readonly (true);
}
var->add_meta ($5);
$$ = var;
}
@@ -246,12 +253,11 @@ formal_param
// Grab the current declaration type, modify it to be array
TypeSpec t = oslcompiler->current_typespec();
t.make_array ($4);
ASTvariable_declaration *var;
var = new ASTvariable_declaration (oslcompiler, t,
auto var = new ASTvariable_declaration (oslcompiler, t,
ustring($3), $5 /*init*/,
oslcompiler->declaring_shader_formals() /*isparam*/,
false /*ismeta*/, $1 /*isoutput*/,
true /* initializer list */);
true /* initlist */, @3.first_line);
var->add_meta ($6);
$$ = var;
}
@@ -259,16 +265,18 @@ formal_param
{
// Grab the current declaration type, modify it to be array
TypeSpec t = oslcompiler->current_typespec();
if (! t.is_structure())
if (! t.is_structure() && ! t.is_triple() && ! t.is_matrix())
oslcompiler->error (oslcompiler->filename(),
oslcompiler->lineno(),
"Can't use '= {...}' initializer except with arrays or struct (%s)", $3);
ASTvariable_declaration *var;
var = new ASTvariable_declaration (oslcompiler, t,
"Can't use '= {...}' initializer "
"except with arrays, structs, vectors, "
"or matrix (%s)", $3);
auto var = new ASTvariable_declaration (oslcompiler, t,
ustring($3), $4 /*init*/,
oslcompiler->declaring_shader_formals() /*isparam*/,
false /*ismeta*/, $1 /*isoutput*/,
true /* initializer list */);
true /* initializer list */,
@3.first_line);
var->add_meta ($5);
$$ = var;
}
@@ -291,10 +299,12 @@ metadata
metadatum
: simple_typename IDENTIFIER initializer
{
ASTvariable_declaration *var;
var = new ASTvariable_declaration (oslcompiler, osllextype($1),
ustring ($2), $3, false,
true /* ismeta */);
auto var = new ASTvariable_declaration (oslcompiler, osllextype($1),
ustring ($2), $3, false /* isparam */,
true /* ismeta */,
false /* isoutput */,
false /* initlist */,
@2.first_line);
$$ = var;
}
| simple_typename IDENTIFIER arrayspec initializer_list
@@ -306,11 +316,11 @@ metadatum
oslcompiler->lineno(),
"Invalid array length for %s", $2);
TypeSpec t (simple, false);
ASTvariable_declaration *var;
var = new ASTvariable_declaration (oslcompiler, t,
auto var = new ASTvariable_declaration (oslcompiler, t,
ustring ($2), $4, false,
true /* ismeata */, false /* output */,
true /* initializer list */);
true /* initializer list */,
@2.first_line);
$$ = var;
}
;
@@ -329,10 +339,10 @@ function_declaration
'(' formal_params_opt ')' metadata_block_opt function_body_or_just_decl
{
oslcompiler->symtab().pop (); // restore scope
ASTfunction_declaration *f;
f = new ASTfunction_declaration (oslcompiler,
auto f = new ASTfunction_declaration (oslcompiler,
typespec_stack.top(),
ustring($2), $5, $8, NULL);
ustring($2), $5, $8, NULL,
@2.first_line);
oslcompiler->remember_function_decl (f);
f->add_meta ($7);
$$ = f;
@@ -346,17 +356,13 @@ struct_declaration
ustring name ($2);
Symbol *s = oslcompiler->symtab().clash (name);
if (s) {
oslcompiler->error (oslcompiler->filename(),
oslcompiler->lineno(),
"\"%s\" already declared in this scope",
name.c_str());
oslcompiler->error (oslcompiler->filename(), oslcompiler->lineno(),
"\"%s\" already declared in this scope", name);
// FIXME -- print the file and line of the other definition
}
if (name[0] == '_' && name[1] == '_' && name[2] == '_') {
oslcompiler->error (oslcompiler->filename(),
oslcompiler->lineno(),
"\"%s\" : sorry, can't start with three underscores",
name.c_str());
if (OIIO::Strutil::starts_with (name, "___")) {
oslcompiler->error (oslcompiler->filename(), oslcompiler->lineno(),
"\"%s\" : sorry, can't start with three underscores", name);
}
oslcompiler->symtab().new_struct (name);
}
@@ -390,7 +396,7 @@ typed_field
oslcompiler->error (oslcompiler->filename(),
oslcompiler->lineno(),
"Field \"%s\" already exists in struct \"%s\"",
name.c_str(), s->name().c_str());
name, s->name());
else
oslcompiler->symtab().add_struct_field (t, name);
$$ = 0;
@@ -404,13 +410,13 @@ typed_field
if (t.arraylength() < 1)
oslcompiler->error (oslcompiler->filename(),
oslcompiler->lineno(),
"Invalid array length for %s", name.c_str());
"Invalid array length for %s", name);
StructSpec *s = oslcompiler->symtab().current_struct();
if (s->lookup_field (name) >= 0)
oslcompiler->error (oslcompiler->filename(),
oslcompiler->lineno(),
"Field \"%s\" already exists in struct \"%s\"",
name.c_str(), s->name().c_str());
name, s->name());
else
oslcompiler->symtab().add_struct_field (t, name);
$$ = 0;
@@ -436,7 +442,9 @@ def_expression
{
TypeSpec t = oslcompiler->current_typespec();
$$ = new ASTvariable_declaration (oslcompiler,
t, ustring($1), $2);
t, ustring($1), $2, false /*isparam*/,
false /*ismeta*/, false /*isoutput*/,
false /*initlist*/, @1.first_line);
}
| IDENTIFIER arrayspec initializer_list_opt
{
@@ -447,20 +455,22 @@ def_expression
oslcompiler->error (oslcompiler->filename(),
oslcompiler->lineno(),
"Invalid array length for %s", $1);
$$ = new ASTvariable_declaration (oslcompiler, t,
$$ = new ASTvariable_declaration (oslcompiler, t,
ustring($1), $3, false, false, false,
true /* initializer list */);
true /* initlist */, @1.first_line);
}
| IDENTIFIER initializer_list
{
TypeSpec t = oslcompiler->current_typespec();
if (! t.is_structure())
if (! t.is_structure() && ! t.is_triple() && ! t.is_matrix())
oslcompiler->error (oslcompiler->filename(),
oslcompiler->lineno(),
"Can't use '= {...}' initializer except with arrays or struct (%s)", $1);
"Can't use '= {...}' initializer "
"except with arrays, struct, vectors, "
"or matrix (%s)", $1);
$$ = new ASTvariable_declaration (oslcompiler, t,
ustring($1), $2, false, false, false,
true /* initializer list */);
true /* initlist */, @1.first_line);
}
;
@@ -486,14 +496,51 @@ compound_initializer
: '{' init_expression_list '}'
{
$$ = new ASTcompound_initializer (oslcompiler, $2);
$$->sourceline (@1.first_line);
}
;
init_expression_list
: init_expression
| init_expression_list ',' init_expression
| init_expression_list_rev ',' init_expression
{
#ifdef OIIO_REFCNT_HAS_RELEASE
// Left recursion is much more efficient for Bison, but
// concatenating the sole last expression ($3) on the
// far end of the running list ($1) leads to an
// inadvertently quadratic algorithm, which is very
// painful for long initializer lists of thousands of
// items (like for a big table). So we use a trick:
// accumulate the list in referse order (lets us prepend
// as O(1) instead of append with O(n)) and then reverse
// it right before we return the list. BUT... note that
// we only do this for sufficiently new OIIO that lets
// us safely convert the ref-counted pointer to a raw
// pointer.
ASTNode::ref revlist = concat ($3, $1);
revlist = reverse (revlist);
$$ = revlist.release ();
#else
// OIIO too old to support reverse(), so just do it
// the old way, normal order.
$$ = concat ($1, $3);
#endif
}
;
init_expression_list_rev
: init_expression
| init_expression_list_rev ',' init_expression
{
#ifdef OIIO_REFCNT_HAS_RELEASE
$$ = concat ($3, $1);
// NOTE: intentionally concat in reverse order!
// Because this is init_expression_list_rev!
#else
// OIIO too old to support reverse(), so just do it
// the old way, normal order.
$$ = concat ($1, $3);
#endif
}
;
@@ -577,15 +624,19 @@ typespec_or_shadertype
}
| IDENTIFIER /* struct name or shader type name */
{
/* N.B. Shader types are considered obsolete. We are
* promoting 'shader' for all, now (OSL 2.0). Some day
* we may add a warning for using the old names.
*/
ustring name ($1);
if (name == "shader")
$$ = ShadTypeGeneric;
$$ = (int)ShaderType::Generic;
else if (name == "surface")
$$ = ShadTypeSurface;
$$ = (int)ShaderType::Surface;
else if (name == "displacement")
$$ = ShadTypeDisplacement;
$$ = (int)ShaderType::Displacement;
else if (name == "volume")
$$ = ShadTypeVolume;
$$ = (int)ShaderType::Volume;
else {
Symbol *s = oslcompiler->symtab().find (name);
if (s && s->is_structure())
@@ -596,7 +647,7 @@ typespec_or_shadertype
oslcompiler->lineno(),
"Unknown struct name: %s", $1);
}
$$ = ShadTypeUnknown;
$$ = (int)ShaderType::Unknown;
}
}
;
@@ -687,6 +738,10 @@ return_statement
{
$$ = new ASTreturn_statement (oslcompiler, $2);
}
| RETURN compound_initializer ';'
{
$$ = new ASTreturn_statement (oslcompiler, $2);
}
;
for_init_statement
@@ -738,9 +793,24 @@ expression
$$ = $2;
} else {
$$ = new ASTunary_expression (oslcompiler, $1, $2);
$$->sourceline (@1.first_line);
}
}
| '(' compound_expression ')' { $$ = $2; }
| '(' compound_expression ')'
{
if ($2->nodetype() == ASTNode::comma_operator_node) {
// Warning for comma operator ïn parenthesized
// expressions, which sometimes happens when somebody
// forgets the proper syntax for triple constructors:
// color x = Cd * (a, b, c); // same as: x = Cd * c
// when they really meant
// color x = Cd * color(a, b, c);
oslcompiler->warning(oslcompiler->filename(),
@1.first_line,
"Comma operator inside parenthesis is probably an error -- it is not a vector/color.");
}
$$ = $2;
}
| function_call
| assign_expression
| ternary_expression
@@ -753,14 +823,17 @@ variable_lvalue
| id_or_field '[' expression ']'
{
$$ = new ASTindex (oslcompiler, $1, $3);
$$->sourceline (@2.first_line);
}
| id_or_field '[' expression ']' '[' expression ']'
{
$$ = new ASTindex (oslcompiler, $1, $3, $6);
$$->sourceline (@2.first_line);
}
| id_or_field '[' expression ']' '[' expression ']' '[' expression ']'
{
$$ = new ASTindex (oslcompiler, $1, $3, $6, $9);
$$->sourceline (@2.first_line);
}
;
@@ -772,6 +845,7 @@ id_or_field
| variable_lvalue '.' IDENTIFIER
{
$$ = new ASTstructselect (oslcompiler, $1, ustring($3));
$$->sourceline (@2.first_line);
}
;
@@ -788,93 +862,111 @@ variable_ref
binary_expression
: expression OR_OP expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::Or, $1, $3);
$$->sourceline (@2.first_line);
}
| expression AND_OP expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::And, $1, $3);
$$->sourceline (@2.first_line);
}
| expression '|' expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::BitOr, $1, $3);
$$->sourceline (@2.first_line);
}
| expression '^' expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::Xor, $1, $3);
$$->sourceline (@2.first_line);
}
| expression '&' expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::BitAnd, $1, $3);
$$->sourceline (@2.first_line);
}
| expression EQ_OP expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::Equal, $1, $3);
$$->sourceline (@2.first_line);
}
| expression NE_OP expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::NotEqual, $1, $3);
$$->sourceline (@2.first_line);
}
| expression '>' expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::Greater, $1, $3);
$$->sourceline (@2.first_line);
}
| expression GE_OP expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::GreaterEqual, $1, $3);
$$->sourceline (@2.first_line);
}
| expression '<' expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::Less, $1, $3);
$$->sourceline (@2.first_line);
}
| expression LE_OP expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::LessEqual, $1, $3);
$$->sourceline (@2.first_line);
}
| expression SHL_OP expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::ShiftLeft, $1, $3);
$$->sourceline (@2.first_line);
}
| expression SHR_OP expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::ShiftRight, $1, $3);
$$->sourceline (@2.first_line);
}
| expression '+' expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::Add, $1, $3);
$$->sourceline (@2.first_line);
}
| expression '-' expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::Sub, $1, $3);
$$->sourceline (@2.first_line);
}
| expression '*' expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::Mul, $1, $3);
$$->sourceline (@2.first_line);
}
| expression '/' expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::Div, $1, $3);
$$->sourceline (@2.first_line);
}
| expression '%' expression
{
$$ = new ASTbinary_expression (oslcompiler,
$$ = new ASTbinary_expression (oslcompiler,
ASTNode::Mod, $1, $3);
$$->sourceline (@2.first_line);
}
;
@@ -901,6 +993,7 @@ type_constructor
{
$$ = new ASTtype_constructor (oslcompiler,
TypeSpec (osllextype ($1)), $3);
$$->sourceline (@1.first_line);
}
;
@@ -908,6 +1001,7 @@ function_call
: IDENTIFIER '(' function_args_opt ')'
{
$$ = new ASTfunction_call (oslcompiler, ustring($1), $3);
$$->sourceline (@1.first_line);
}
;
@@ -918,46 +1012,69 @@ function_args_opt
function_args
: expression
| compound_initializer
| function_args ',' expression { $$ = concat ($1, $3); }
| function_args ',' compound_initializer { $$ = concat ($1, $3); }
;
assign_expression
: variable_lvalue '=' expression
{ $$ = new ASTassign_expression (oslcompiler, $1,
ASTNode::Assign, $3); }
{
$$ = new ASTassign_expression (oslcompiler, $1, ASTNode::Assign, $3);
$$->sourceline (@2.first_line);
}
| variable_lvalue MUL_ASSIGN expression
{ $$ = new ASTassign_expression (oslcompiler, $1,
ASTNode::Mul, $3); }
{
$$ = new ASTassign_expression (oslcompiler, $1, ASTNode::Mul, $3);
$$->sourceline (@2.first_line);
}
| variable_lvalue DIV_ASSIGN expression
{ $$ = new ASTassign_expression (oslcompiler, $1,
ASTNode::Div, $3); }
{
$$ = new ASTassign_expression (oslcompiler, $1, ASTNode::Div, $3);
$$->sourceline (@2.first_line);
}
| variable_lvalue ADD_ASSIGN expression
{ $$ = new ASTassign_expression (oslcompiler, $1,
ASTNode::Add, $3); }
{
$$ = new ASTassign_expression (oslcompiler, $1, ASTNode::Add, $3);
$$->sourceline (@2.first_line);
}
| variable_lvalue SUB_ASSIGN expression
{ $$ = new ASTassign_expression (oslcompiler, $1,
ASTNode::Sub, $3); }
{
$$ = new ASTassign_expression (oslcompiler, $1, ASTNode::Sub, $3);
$$->sourceline (@2.first_line);
}
| variable_lvalue BIT_AND_ASSIGN expression
{ $$ = new ASTassign_expression (oslcompiler, $1,
ASTNode::BitAnd, $3); }
{
$$ = new ASTassign_expression (oslcompiler, $1, ASTNode::BitAnd, $3);
$$->sourceline (@2.first_line);
}
| variable_lvalue BIT_OR_ASSIGN expression
{ $$ = new ASTassign_expression (oslcompiler, $1,
ASTNode::BitOr, $3); }
{
$$ = new ASTassign_expression (oslcompiler, $1, ASTNode::BitOr, $3);
$$->sourceline (@2.first_line);
}
| variable_lvalue XOR_ASSIGN expression
{ $$ = new ASTassign_expression (oslcompiler, $1,
ASTNode::Xor, $3); }
{
$$ = new ASTassign_expression (oslcompiler, $1, ASTNode::Xor, $3);
$$->sourceline (@2.first_line);
}
| variable_lvalue SHL_ASSIGN expression
{ $$ = new ASTassign_expression (oslcompiler, $1,
ASTNode::ShiftLeft, $3); }
{
$$ = new ASTassign_expression (oslcompiler, $1, ASTNode::ShiftLeft, $3);
$$->sourceline (@2.first_line);
}
| variable_lvalue SHR_ASSIGN expression
{ $$ = new ASTassign_expression (oslcompiler, $1,
ASTNode::ShiftRight, $3); }
{
$$ = new ASTassign_expression (oslcompiler, $1, ASTNode::ShiftRight, $3);
$$->sourceline (@2.first_line);
}
;
ternary_expression
: expression '?' expression ':' expression
{
$$ = new ASTternary_expression (oslcompiler, $1, $3, $5);
$$->sourceline (@2.first_line);
}
;
+99 -71
View File
@@ -119,6 +119,12 @@ using namespace OSL::pvt;
#endif
#endif
// flex itself will generate fatal warnings about signed vs unsigned.
// Bypass that nonsense.
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 6
#pragma GCC diagnostic ignored "-Wsign-compare"
#endif
void preprocess (const char *yytext);
// Macro that sets the yylloc line variables to the current parse line.
@@ -134,7 +140,7 @@ void preprocess (const char *yytext);
************************************************/
/* preprocessor symbols */
{CPP} { preprocess (yytext); SETLINE; }
{CPP} { preprocess (yytext); SETLINE; }
/* Comments */
{CPLUSCOMMENT} { oslcompiler->incr_lineno(); /* skip it */
@@ -142,32 +148,32 @@ void preprocess (const char *yytext);
}
/* keywords */
"break" { SETLINE; return (yylval.i=BREAK); }
"closure" { SETLINE; return (yylval.i=CLOSURE); }
"color" { SETLINE; return (yylval.i=COLORTYPE); }
"continue" { SETLINE; return (yylval.i=CONTINUE); }
"do" { SETLINE; return (yylval.i=DO); }
"else" { SETLINE; return (yylval.i=ELSE); }
"float" { SETLINE; return (yylval.i=FLOATTYPE); }
"for" { SETLINE; return (yylval.i=FOR); }
"if" { SETLINE; return (yylval.i=IF_TOKEN); }
"illuminance" { SETLINE; return (yylval.i=ILLUMINANCE); }
"illuminate" { SETLINE; return (yylval.i=ILLUMINATE); }
"int" { SETLINE; return (yylval.i=INTTYPE); }
"matrix" { SETLINE; return (yylval.i=MATRIXTYPE); }
"normal" { SETLINE; return (yylval.i=NORMALTYPE); }
"break" { SETLINE; return (yylval.i=BREAK); }
"closure" { SETLINE; return (yylval.i=CLOSURE); }
"color" { SETLINE; return (yylval.i=COLORTYPE); }
"continue" { SETLINE; return (yylval.i=CONTINUE); }
"do" { SETLINE; return (yylval.i=DO); }
"else" { SETLINE; return (yylval.i=ELSE); }
"float" { SETLINE; return (yylval.i=FLOATTYPE); }
"for" { SETLINE; return (yylval.i=FOR); }
"if" { SETLINE; return (yylval.i=IF_TOKEN); }
"illuminance" { SETLINE; return (yylval.i=ILLUMINANCE); }
"illuminate" { SETLINE; return (yylval.i=ILLUMINATE); }
"int" { SETLINE; return (yylval.i=INTTYPE); }
"matrix" { SETLINE; return (yylval.i=MATRIXTYPE); }
"normal" { SETLINE; return (yylval.i=NORMALTYPE); }
"output" { SETLINE; return (yylval.i=OUTPUT); }
"point" { SETLINE; return (yylval.i=POINTTYPE); }
"public" { SETLINE; return (yylval.i=PUBLIC); }
"return" { SETLINE; return (yylval.i=RETURN); }
"string" { SETLINE; return (yylval.i=STRINGTYPE); }
"struct" { SETLINE; return (yylval.i=STRUCT); }
"vector" { SETLINE; return (yylval.i=VECTORTYPE); }
"void" { SETLINE; return (yylval.i=VOIDTYPE); }
"while" { SETLINE; return (yylval.i=WHILE); }
"or" { SETLINE; return (yylval.i=OR_OP); }
"and" { SETLINE; return (yylval.i=AND_OP); }
"not" { SETLINE; return (yylval.i=NOT_OP); }
"point" { SETLINE; return (yylval.i=POINTTYPE); }
"public" { SETLINE; return (yylval.i=PUBLIC); }
"return" { SETLINE; return (yylval.i=RETURN); }
"string" { SETLINE; return (yylval.i=STRINGTYPE); }
"struct" { SETLINE; return (yylval.i=STRUCT); }
"vector" { SETLINE; return (yylval.i=VECTORTYPE); }
"void" { SETLINE; return (yylval.i=VOIDTYPE); }
"while" { SETLINE; return (yylval.i=WHILE); }
"or" { SETLINE; return (yylval.i=OR_OP); }
"and" { SETLINE; return (yylval.i=AND_OP); }
"not" { SETLINE; return (yylval.i=NOT_OP); }
/* reserved words */
"bool"|"case"|"char"|"class"|"const"|"default"|"double" | \
@@ -175,17 +181,17 @@ void preprocess (const char *yytext);
"protected"|"short"|"signed"|"sizeof"|"static"|"struct" | \
"switch"|"template"|"this"|"true"|"typedef"|"uniform" | \
"union"|"unsigned"|"varying"|"virtual" {
fprintf (stderr, "Error: \"%s\", line %d:\n"
"\t'%s' is a reserved word\n",
oslcompiler->filename().c_str(),
oslcompiler->lineno(), yytext);
oslcompiler->error (oslcompiler->filename(),
oslcompiler->lineno(),
"'%s' is a reserved word",
yytext);
SETLINE;
return (yylval.i=RESERVED);
}
/* Identifiers */
{IDENT} {
{IDENT} {
yylval.s = ustring(yytext).c_str();
SETLINE;
return IDENTIFIER;
@@ -241,23 +247,23 @@ void preprocess (const char *yytext);
* catch-all rule, but we need to define the two-character operators
* so they are not lexed as '+' and '=' separately, for example.
*/
"+=" { SETLINE; return (yylval.i=ADD_ASSIGN); }
"-=" { SETLINE; return (yylval.i=SUB_ASSIGN); }
"*=" { SETLINE; return (yylval.i=MUL_ASSIGN); }
"/=" { SETLINE; return (yylval.i=DIV_ASSIGN); }
"&=" { SETLINE; return (yylval.i=BIT_AND_ASSIGN); }
"|=" { SETLINE; return (yylval.i=BIT_OR_ASSIGN); }
"^=" { SETLINE; return (yylval.i=XOR_ASSIGN); }
"<<=" { SETLINE; return (yylval.i=SHL_ASSIGN); }
">>=" { SETLINE; return (yylval.i=SHR_ASSIGN); }
"<<" { SETLINE; return (yylval.i=SHL_OP); }
">>" { SETLINE; return (yylval.i=SHR_OP); }
"&&" { SETLINE; return (yylval.i=AND_OP); }
"||" { SETLINE; return (yylval.i=OR_OP); }
"<=" { SETLINE; return (yylval.i=LE_OP); }
">=" { SETLINE; return (yylval.i=GE_OP); }
"==" { SETLINE; return (yylval.i=EQ_OP); }
"!=" { SETLINE; return (yylval.i=NE_OP); }
"+=" { SETLINE; return (yylval.i=ADD_ASSIGN); }
"-=" { SETLINE; return (yylval.i=SUB_ASSIGN); }
"*=" { SETLINE; return (yylval.i=MUL_ASSIGN); }
"/=" { SETLINE; return (yylval.i=DIV_ASSIGN); }
"&=" { SETLINE; return (yylval.i=BIT_AND_ASSIGN); }
"|=" { SETLINE; return (yylval.i=BIT_OR_ASSIGN); }
"^=" { SETLINE; return (yylval.i=XOR_ASSIGN); }
"<<=" { SETLINE; return (yylval.i=SHL_ASSIGN); }
">>=" { SETLINE; return (yylval.i=SHR_ASSIGN); }
"<<" { SETLINE; return (yylval.i=SHL_OP); }
">>" { SETLINE; return (yylval.i=SHR_OP); }
"&&" { SETLINE; return (yylval.i=AND_OP); }
"||" { SETLINE; return (yylval.i=OR_OP); }
"<=" { SETLINE; return (yylval.i=LE_OP); }
">=" { SETLINE; return (yylval.i=GE_OP); }
"==" { SETLINE; return (yylval.i=EQ_OP); }
"!=" { SETLINE; return (yylval.i=NE_OP); }
"++" { SETLINE; return (yylval.i=INCREMENT); }
"--" { SETLINE; return (yylval.i=DECREMENT); }
@@ -265,17 +271,17 @@ void preprocess (const char *yytext);
"[[" { SETLINE; return (yylval.i=METADATA_BEGIN); }
/* End of line */
"\\\n" |
[\n] { oslcompiler->incr_lineno();
"\\\n" |
[\n] { oslcompiler->incr_lineno();
SETLINE;
}
/* Ignore whitespace */
{WHITE} { }
{WHITE} { }
/* catch-all rule for any other single characters */
! { SETLINE; return (yylval.i = NOT_OP); }
. { SETLINE; return (yylval.i = *yytext); }
! { SETLINE; return (yylval.i = NOT_OP); }
. { SETLINE; return (yylval.i = *yytext); }
%%
@@ -290,29 +296,54 @@ preprocess (const char *yytext)
while (*p == ' ' || *p == '\t')
p++;
if (*p != '#') {
fprintf (stderr, "Possible bug in shader preprocess\n");
oslcompiler->error (oslcompiler->filename(), oslcompiler->lineno(),
"Possible bug in shader preprocess");
SETLINE;
return;
return;
}
p++;
while (*p == ' ' || *p == '\t')
p++;
if (! strncmp (p, "pragma", 6)) {
// pragma
fprintf (stderr, "Unknown pragma '%s'\n", p);
// pragma
OIIO::string_view line (p+6);
string_view pragmatype = OIIO::Strutil::parse_word (line);
if (OIIO::Strutil::iequals (pragmatype, "osl")) {
string_view pragmaname = OIIO::Strutil::parse_word (line);
if (pragmaname == "nowarn") {
oslcompiler->pragma_nowarn ();
} else {
oslcompiler->warning (oslcompiler->filename(), oslcompiler->lineno(),
"Unknown pragma '%s'", pragmaname);
}
}
// N.B. Pragmas that don't start with "osl" are ignored
oslcompiler->incr_lineno(); // the pragma ends with an EOLN
} else { /* probably the line number and filename */
if (! strncmp (p, "line", 4))
p += 4;
int line = atoi (p);
if (line > 0) {
const char *f = strchr (yytext, '\"');
if (f) {
const char *f = strchr (yytext, '\"');
if (f) {
++f; // increment to past the quote
int len = 0; // count of chars within quotes
while (f[len] && f[len] != '\"')
++len;
int len = 0; // count of chars within quotes
while (f[len] && f[len] != '\"')
++len;
std::string filename (f, len);
#if defined(_WIN32) && defined(USE_BOOST_WAVE) && (USE_BOOST_WAVE != 0)
// Assuming boost is the culprit and escaping Windows path
// separators incorrectly which clang's preprocessor won't do.
// Should this just be for Windows CI builds?
auto replace_all = [](std::string& str, const std::string& from, const std::string& to) {
size_t start = 0;
while((start = str.find(from, start)) != std::string::npos) {
str.replace(start, from.size(), to);
start += to.size();
}
};
replace_all( filename, "\\\\", "\\");
#endif
// Make it relative to the working directory, so error output
// isn't hugely cluttered (and also to make Boost::wave's
// error output match the standard cpp.
@@ -322,7 +353,7 @@ preprocess (const char *yytext)
(filename[0] == '/' || filename[0] == '\\'))
filename.erase (0, 1);
}
oslcompiler->filename (ustring (filename));
oslcompiler->filename (ustring (filename));
// Spooky workaround for Boost Wave bug: force_include
// is broken and doesn't give us the right lines/files, so
// instead we forcefully insert a '#include "stdosl.h"' into
@@ -333,10 +364,9 @@ preprocess (const char *yytext)
--line;
}
oslcompiler->lineno (line);
} else {
fprintf (stderr, "Error: \"%s\", line %d:\n"
"\tUnrecognized preprocessor command: #%s\n",
oslcompiler->filename().c_str(), oslcompiler->lineno(), p);
} else {
oslcompiler->error (oslcompiler->filename(), oslcompiler->lineno(),
"Unrecognized preprocessor command: #%s", p);
}
}
SETLINE;
@@ -351,9 +381,8 @@ namespace pvt { // OSL::pvt
bool
OSLCompilerImpl::osl_parse_buffer (const std::string &preprocessed_buffer)
{
// Thread safety with the lexer/parser
static std::mutex oslcompiler_mutex;
std::lock_guard<std::mutex> lock (oslcompiler_mutex);
// N.B. This should only be called if oslcompiler_mutex is held.
ASSERT (oslcompiler == this);
#ifndef OIIO_STRUTIL_HAS_STOF
// Force classic "C" locale for correct '.' decimal parsing.
@@ -365,7 +394,6 @@ OSLCompilerImpl::osl_parse_buffer (const std::string &preprocessed_buffer)
#endif
osl_switch_to_buffer (osl_scan_string (preprocessed_buffer.c_str()));
oslcompiler = this;
oslparse ();
bool parseerr = error_encountered();
osl_delete_buffer (YY_CURRENT_BUFFER);
+1046 -265
View File
File diff suppressed because it is too large Load Diff
+77 -3
View File
@@ -69,7 +69,7 @@ MACRO ( LLVM_COMPILE llvm_src srclist )
foreach (def ${CURRENT_DEFINITIONS})
set (LLVM_COMPILE_FLAGS ${LLVM_COMPILE_FLAGS} "-D${def}")
endforeach()
set (LLVM_COMPILE_FLAGS ${LLVM_COMPILE_FLAGS} ${SIMD_COMPILE_FLAGS} ${CSTD_FLAGS})
set (LLVM_COMPILE_FLAGS ${LLVM_COMPILE_FLAGS} ${SIMD_COMPILE_FLAGS} ${CSTD_FLAGS} ${TOOLCHAIN_FLAGS})
# Figure out what program we will use to make the bitcode.
if (NOT LLVM_BC_GENERATOR)
@@ -117,15 +117,82 @@ MACRO ( LLVM_COMPILE llvm_src srclist )
-Wno-deprecated-register
-O3 -fno-math-errno -S -emit-llvm -o ${llvm_asm} ${llvm_src}
COMMAND "${LLVM_DIRECTORY}/bin/llvm-as" -f -o ${llvm_bc} ${llvm_asm}
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/serialize-bc.bash" ${llvm_bc} ${llvm_bc_cpp}
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/serialize-bc.bash" ${llvm_bc} ${llvm_bc_cpp} "osl_llvm_compiled_ops"
MAIN_DEPENDENCY ${llvm_src}
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/serialize-bc.bash"
${exec_headers} ${PROJECT_PUBLIC_HEADERS}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )
ENDMACRO ( )
# Function to compile a C++ source file to CUDA-compatible LLVM bitcode
FUNCTION ( MAKE_CUDA_BITCODE src generated_bc )
GET_FILENAME_COMPONENT ( src_we ${src} NAME_WE )
SET ( asm_cuda "${CMAKE_CURRENT_BINARY_DIR}/${src_we}_cuda.s" )
SET ( bc_cuda "${CMAKE_CURRENT_BINARY_DIR}/${src_we}_cuda.bc" )
ADD_CUSTOM_COMMAND ( OUTPUT ${bc_cuda}
COMMAND ${LLVM_BC_GENERATOR}
${LLVM_COMPILE_FLAGS}
"-I${CMAKE_CURRENT_SOURCE_DIR}"
"-I${CMAKE_SOURCE_DIR}/src/include"
"-I${CMAKE_BINARY_DIR}/include"
"-I${OPENIMAGEIO_INCLUDE_DIR}"
"-I${ILMBASE_INCLUDE_DIR}"
"-I${Boost_INCLUDE_DIRS}"
-D__CUDACC__ -DOSL_COMPILING_TO_BITCODE=1 -DNDEBUG -DOIIO_NO_SSE
--language=cuda --cuda-device-only --cuda-gpu-arch=${CUDA_TARGET_ARCH}
${CUDA_LIB_FLAGS}
-std=c++11 -Wno-deprecated-register
-O3 -fno-math-errno -S -emit-llvm -o ${asm_cuda} ${src}
COMMAND "${LLVM_DIRECTORY}/bin/llvm-as" -f -o ${bc_cuda} ${asm_cuda}
DEPENDS ${exec_headers} ${PROJECT_PUBLIC_HEADERS} ${src}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )
SET ( ${generated_bc} ${bc_cuda} PARENT_SCOPE )
ENDFUNCTION ()
MACRO ( CUDA_SHADEOPS_COMPILE srclist )
# Add all of the "shadeops" sources that need to be compiled to LLVM bitcode for CUDA
set ( shadeops_srcs
llvm_ops.cpp
opnoise.cpp
../liboslnoise/simplexnoise.cpp
)
SET ( shadeops_bc_cuda_cpp "${CMAKE_CURRENT_BINARY_DIR}/shadeops_cuda.bc.cpp" )
SET ( linked_shadeops_bc "${CMAKE_CURRENT_BINARY_DIR}/linked_shadeops.bc" )
LIST ( APPEND ${srclist} ${shadeops_bc_cuda_cpp} )
FOREACH ( shadeops_src ${shadeops_srcs} )
MAKE_CUDA_BITCODE ( ${shadeops_src} shadeops_bc )
LIST ( APPEND shadeops_bc_list ${shadeops_bc} )
ENDFOREACH ()
# Link all of the individual LLVM bitcode files
ADD_CUSTOM_COMMAND ( OUTPUT ${linked_shadeops_bc}
COMMAND "${LLVM_DIRECTORY}/bin/llvm-link" -internalize ${shadeops_bc_list} -o ${linked_shadeops_bc}
DEPENDS ${shadeops_bc_list} ${exec_headers} ${PROJECT_PUBLIC_HEADERS} ${shadeops_srcs}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )
# Serialze the linked bitcode into a CPP file and add it to the list of liboslexec soures
ADD_CUSTOM_COMMAND ( OUTPUT ${shadeops_bc_cuda_cpp}
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/serialize-bc.bash"
${linked_shadeops_bc} ${shadeops_bc_cuda_cpp} "osl_llvm_compiled_ops_cuda"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/serialize-bc.bash" ${linked_shadeops_bc}
${exec_headers} ${PROJECT_PUBLIC_HEADERS}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )
ENDMACRO ( )
if (USE_LLVM_BITCODE)
LLVM_COMPILE ( llvm_ops.cpp liboslexec_srcs )
# Optionally repeat the bitcode compilation with CUDA-specific options
if (CUDA_FOUND)
ADD_DEFINITIONS (-DOSL_LLVM_CUDA_BITCODE)
CUDA_SHADEOPS_COMPILE ( liboslexec_srcs )
endif ()
else ()
# With MSVC/Mingw, we don't compile llvm_ops.cpp to LLVM bitcode, due
# to clang being unable to compile MSVC C++ header files at this time.
@@ -138,6 +205,14 @@ if (BUILDSTATIC)
ADD_LIBRARY ( oslexec STATIC ${liboslexec_srcs} )
else ()
ADD_LIBRARY ( oslexec SHARED ${liboslexec_srcs} )
if (VERBOSE)
message(STATUS "Setting SOVERSION to: ${SOVERSION}")
endif ()
set_target_properties( oslexec
PROPERTIES
VERSION ${OSL_VERSION_MAJOR}.${OSL_VERSION_MINOR}.${OSL_VERSION_PATCH}
SOVERSION ${SOVERSION} )
endif ()
TARGET_LINK_LIBRARIES ( oslexec
@@ -147,7 +222,6 @@ TARGET_LINK_LIBRARIES ( oslexec
${PARTIO_LIBRARIES} ${ZLIB_LIBRARIES}
${Boost_LIBRARIES} ${CMAKE_DL_LIBS}
${CLANG_LIBRARIES}
${LLVM_LIBRARY} ${LLVM_MCJIT_LIBRARY}
${LLVM_LIBRARIES} ${LLVM_LDFLAGS}
${LLVM_SYSTEM_LIBRARIES})
ADD_DEPENDENCIES (oslexec "${CMAKE_SOURCE_DIR}/src/build-scripts/hidesymbols.map")
+314 -16
View File
@@ -97,6 +97,7 @@ BackendLLVM::BackendLLVM (ShadingSystemImpl &shadingsys,
// getcwd inside LLVM. Oy.
check_cwd (shadingsys);
#endif
m_use_optix = shadingsys.renderer()->supports ("OptiX");
}
@@ -112,10 +113,10 @@ BackendLLVM::llvm_debug() const
{
if (shadingsys().llvm_debug() == 0)
return 0;
if (shadingsys().debug_groupname() &&
if (!shadingsys().debug_groupname().empty() &&
shadingsys().debug_groupname() != group().name())
return 0;
if (inst() && shadingsys().debug_layername() &&
if (inst() && !shadingsys().debug_layername().empty() &&
shadingsys().debug_layername() != inst()->layername())
return 0;
return shadingsys().llvm_debug();
@@ -323,6 +324,215 @@ BackendLLVM::getOrAllocateLLVMSymbol (const Symbol& sym)
llvm::Value*
BackendLLVM::addCUDAVariable(const std::string& name, int size, int alignment,
void* data, const std::string& type)
{
ASSERT (use_optix() && "This function is only supposed to be used with OptiX!");
llvm::Constant* constant = nullptr;
if (type == "float") {
constant = llvm::ConstantFP::get (
llvm::Type::getFloatTy (ll.module()->getContext()), *(float*) data);
}
else if (type == "int") {
constant = llvm::ConstantInt::get (
llvm::Type::getInt32Ty (ll.module()->getContext()), *(int*) data);
}
else if (type == "string") {
// Register the string with the OptiX renderer. The renderer will add
// the string to a global table and create an OptiX variable to hold the
// char*.
shadingsys().renderer()->register_string (((ustring*)data)->string(), name);
// Add the metadata needed by OptiX to access the variable.
createOptixMetadata (name, "string", 8);
// Leave the variable uninitialized to prevent raw pointers from
// appearing in the generated code. The OptiX renderer will set the
// variable to the string address before the kernel is launched.
constant = llvm::ConstantInt::get (
llvm::Type::getInt64Ty (ll.module()->getContext()), 0);
m_varname_map [name] = ((ustring*)data)->string();
}
else {
// Handle unspecified types as generic byte arrays
llvm::ArrayRef<uint8_t> arr_ref ((uint8_t*)data, size);
constant = llvm::ConstantDataArray::get (ll.module()->getContext(), arr_ref);
}
llvm::GlobalVariable* g_var = reinterpret_cast<llvm::GlobalVariable*>(
ll.module()->getOrInsertGlobal (name, constant->getType()));
ASSERT (g_var && "Unable to create GlobalVariable");
g_var->setAlignment (alignment);
g_var->setLinkage (llvm::GlobalValue::ExternalLinkage);
g_var->setVisibility (llvm::GlobalValue::DefaultVisibility);
g_var->setInitializer(constant);
m_const_map[name] = g_var;
return g_var;
}
llvm::Value*
BackendLLVM::createOptixVariable (const std::string& name, const std::string& type,
int size, void* data)
{
ASSERT (use_optix() && "This function is only supported when using OptiX!");
// Return the Value if it has already been allocated
std::map<std::string, llvm::GlobalVariable*>::iterator it =
get_const_map().find (name);
if (it != get_const_map().end()) {
return it->second;
}
int alignment =
(type == "float" ) ? 4 :
(type == "int" ) ? 4 :
(type == "color" ) ? 8 :
(type == "string") ? 8 : 8;
// Create a global variable with the name, type, and initializer. This is
// the value that will be accessed when the shader executes.
llvm::Value* g_var = addCUDAVariable (name, size, alignment, data, type);
if (g_var == nullptr) {
ASSERT (0 && "Unable to create OptiX variable");
}
createOptixMetadata (name, type, size);
return g_var;
}
void
BackendLLVM::createOptixMetadata (const std::string& name, const std::string& type,
int size)
{
// Create additional variables with the semantic information needed by OptiX
// to access the global variable created above.
//
// There is no need to retain pointers to these variables, since they are not
// accessed during execution. They are only used internally by OptiX.
//
// Refer to the OptiX API documentation and optix_defines.h in the OptiX SDK
// for more information.
ASSERT (use_optix() && "This function is only supported when using OptiX!");
auto mangle_name = [](const std::string& name, const std::string& prefix) {
return OIIO::Strutil::format ("_ZN%drti_internal_%s%d%sE",
prefix.size()+13, prefix, name.size(), name);
};
const std::string optix_type =
(type == "color" ) ? "float3" :
(type == "string") ? "uint64_t" :
type;
// Copy the OptiX typename contents into a temporary vector
std::vector<char> type_name (optix_type.c_str(),
optix_type.c_str() + optix_type.size() + 1);
struct rti_typeinfo {
unsigned int kind = 0x796152; // _OPTIX_VARIABLE
unsigned int size;
} type_info;
type_info.size = size;
int type_enum = 0x1337; // _OPTIX_TYPE_ENUM_UNKNOWN
char empty = 0;
addCUDAVariable (mangle_name (name, "typeinfo" ), 8, 4, &type_info, "");
addCUDAVariable (mangle_name (name, "typename" ), type_name.size(), 16, type_name.data(), "");
addCUDAVariable (mangle_name (name, "typeenum" ), 4, 4, &type_enum, "int");
addCUDAVariable (mangle_name (name, "semantic" ), 1, 1, &empty, "");
addCUDAVariable (mangle_name (name, "annotation"), 1, 1, &empty, "");
}
llvm::Value *
BackendLLVM::getOrAllocateCUDAVariable (const Symbol& sym)
{
ASSERT (use_optix() && "This function is only supported when using OptiX!");
std::stringstream ss;
if (sym.typespec().is_string()) {
// Use the ustring hash to create a name for the symbol that's based on
// the string contents
//
// TODO: Collisions between variable names are unlikely, but stil
// possible. Using something like a counter to handle collisions
// is unattractive because it depends on the order in which
// strings are encountered at run time.
//
// For now I am simply appending the length to the hash, but a
// more robust solution may be called for.
ss << "ds_"
<< std::setbase (16) << std::setfill('0') << std::setw (16)
<< (*(ustring *)sym.data()).hash()
<< "_"
<< std::setbase (16) << std::setfill('0') << std::setw (4)
<< (*(ustring *)sym.data()).length();
auto it = m_varname_map.find(ss.str());
const std::string old_str = (it != m_varname_map.end())
? it->second : "";
if (old_str != "" && old_str != (*(ustring *)sym.data()).string()) {
std::cerr << "Warning: variable name collision between " << old_str
<< " and " << (*(ustring *)sym.data()).string()
<< std::endl;
}
}
else {
// PTX doesn't like leading dollar signs, so prepend an underscore
if (sym.name()[0] == '$') {
ss << '_';
}
ss << sym.name();
}
const std::string name = ss.str();
// Return the Value if it has already been allocated
std::map<std::string, llvm::GlobalVariable*>::iterator it =
get_const_map().find (name);
if (it != get_const_map().end()) {
return it->second;
}
int alignment =
(sym.typespec().is_scalarnum()) ? 4 :
(sym.typespec().is_triple() ) ? 8 :
(sym.typespec().is_array() ) ? 8 :
(sym.typespec().is_string() ) ? 8 : -1;
if (alignment < 1) {
return nullptr;
}
return addCUDAVariable (name, sym.size(), alignment, sym.data(),
sym.typespec().string());
}
llvm::Value *
BackendLLVM::llvm_get_pointer (const Symbol& sym, int deriv,
llvm::Value *arrayindex)
@@ -336,9 +546,23 @@ BackendLLVM::llvm_get_pointer (const Symbol& sym, int deriv,
llvm::Value *result = NULL;
if (sym.symtype() == SymTypeConst) {
// For constants, start with *OUR* pointer to the constant values.
result = ll.ptr_cast (ll.constant_ptr (sym.data()),
ll.type_ptr (llvm_type(sym.typespec().elementtype())));
if (use_optix()) {
// Check the constant map for the named Symbol; if it's found, then
// a GlobalVariable has been created for it
llvm::Value* ptr = getOrAllocateCUDAVariable (sym);
if (ptr) {
llvm::Type *cast_type = (! sym.typespec().is_string())
? ll.type_ptr (llvm_type(sym.typespec().elementtype()))
: ll.type_void_ptr();
result = ll.ptr_cast (ptr, cast_type);
}
}
else {
// For constants, start with *OUR* pointer to the constant values.
result = ll.ptr_cast (ll.constant_ptr (sym.data()),
ll.type_ptr (llvm_type(sym.typespec().elementtype())));
}
} else {
// Start with the initial pointer to the variable's memory location
@@ -444,12 +668,34 @@ BackendLLVM::llvm_load_value (llvm::Value *ptr, const TypeSpec &type,
result = ll.op_float_to_int (result);
else if (type.is_int() && cast == TypeDesc::TypeFloat)
result = ll.op_int_to_float (result);
else if (type.is_string() && cast == TypeDesc::UINT64)
result = ll.ptr_to_cast (result, ll.type_longlong());
return result;
}
llvm::Value *
BackendLLVM::llvm_load_device_string (const Symbol& sym, bool follow)
{
// TODO: need to make this work with arrays of strings
ASSERT (use_optix() && "This is only intended to be used with CUDA");
llvm::Value* val = (sym.is_constant() || sym.data())
? getOrAllocateCUDAVariable (sym)
: llvm_load_value (sym, 0, nullptr, 0, TypeDesc(TypeDesc::UINT64));
// Typically, the address of the string is held in a global variable, so we
// need to dereference the global to get to the char*.
if (follow)
val = ll.int_to_ptr_cast (ll.op_load (val));
return val;
}
llvm::Value *
BackendLLVM::llvm_load_constant_value (const Symbol& sym,
int arrayindex, int component,
@@ -483,6 +729,10 @@ BackendLLVM::llvm_load_constant_value (const Symbol& sym,
int ncomps = (int) sym.typespec().aggregate();
return ll.constant (val[ncomps*arrayindex + component]);
}
if (sym.typespec().is_string() && use_optix()) {
// TODO: This ignores arrayindex
return llvm_load_device_string (sym);
}
if (sym.typespec().is_string()) {
const ustring *val = (const ustring *)sym.data();
return ll.constant (val[arrayindex]);
@@ -686,6 +936,8 @@ BackendLLVM::llvm_call_function (const char *name,
const Symbol &s = *(symargs[i]);
if (s.typespec().is_closure())
valargs[i] = llvm_load_value (s);
else if (use_optix() && s.typespec().is_string())
valargs[i] = llvm_load_device_string (s);
else if (s.typespec().simpletype().aggregate > 1 ||
(deriv_ptrs && s.has_derivs()))
valargs[i] = llvm_void_ptr (s);
@@ -767,7 +1019,7 @@ BackendLLVM::llvm_test_nonzero (Symbol &val, bool test_derivs)
bool
BackendLLVM::llvm_assign_impl (Symbol &Result, Symbol &Src,
int arrayindex)
int arrayindex, int srccomp, int dstcomp)
{
ASSERT (! Result.typespec().is_structure());
ASSERT (! Src.typespec().is_structure());
@@ -825,29 +1077,75 @@ BackendLLVM::llvm_assign_impl (Symbol &Result, Symbol &Src,
// Remember that llvm_load_value will automatically convert scalar->triple.
TypeDesc rt = Result.typespec().simpletype();
TypeDesc basetype = TypeDesc::BASETYPE(rt.basetype);
int num_components = rt.aggregate;
for (int i = 0; i < num_components; ++i) {
const int num_components = rt.aggregate;
const bool singlechan = (srccomp != -1) || (dstcomp != -1);
if (use_optix() && Src.typespec().is_string()) {
// We defer the loading of the char* until the assigned value is
// actually used, so just pass the value of the global variable.
llvm::Value* src = llvm_load_device_string (Src, false);
llvm_store_value (ll.ptr_cast (src, ll.type_void_ptr()), Result);
}
else if (!singlechan) {
for (int i = 0; i < num_components; ++i) {
llvm::Value* src_val = Src.is_constant()
? llvm_load_constant_value (Src, arrayindex, i, basetype)
: llvm_load_value (Src, 0, arrind, i, basetype);
if (!src_val)
return false;
llvm_store_value (src_val, Result, 0, arrind, i);
}
} else {
// connect individual component of an aggregate type
// set srccomp to 0 for case when src is actually a float
if (srccomp == -1) srccomp = 0;
llvm::Value* src_val = Src.is_constant()
? llvm_load_constant_value (Src, arrayindex, i, basetype)
: llvm_load_value (Src, 0, arrind, i, basetype);
? llvm_load_constant_value (Src, arrayindex, srccomp, basetype)
: llvm_load_value (Src, 0, arrind, srccomp, basetype);
if (!src_val)
return false;
llvm_store_value (src_val, Result, 0, arrind, i);
// write source float into all compnents when dstcomp == -1, otherwise
// the single element requested.
if (dstcomp == -1) {
for (int i = 0; i < num_components; ++i)
llvm_store_value (src_val, Result, 0, arrind, i);
} else
llvm_store_value (src_val, Result, 0, arrind, dstcomp);
}
// Handle derivatives
if (Result.has_derivs()) {
if (Src.has_derivs()) {
// src and result both have derivs -- copy them
for (int d = 1; d <= 2; ++d) {
for (int i = 0; i < num_components; ++i) {
llvm::Value* val = llvm_load_value (Src, d, arrind, i);
llvm_store_value (val, Result, d, arrind, i);
if (!singlechan) {
for (int d = 1; d <= 2; ++d) {
for (int i = 0; i < num_components; ++i) {
llvm::Value* val = llvm_load_value (Src, d, arrind, i);
llvm_store_value (val, Result, d, arrind, i);
}
}
} else {
for (int d = 1; d <= 2; ++d) {
llvm::Value* val = llvm_load_value (Src, d, arrind, srccomp);
if (dstcomp == -1) {
for (int i = 0; i < num_components; ++i)
llvm_store_value (val, Result, d, arrind, i);
}
else
llvm_store_value (val, Result, d, arrind, dstcomp);
}
}
} else {
// Result wants derivs but src didn't have them -- zero them
llvm_zero_derivs (Result);
if (dstcomp != -1) {
// memset the single deriv component's to zero
if (Result.has_derivs() && Result.typespec().elementtype().is_floatbased()) {
// dx
ll.op_memset (ll.GEP(llvm_void_ptr(Result,1), dstcomp), 0, 1, rt.basesize());
// dy
ll.op_memset (ll.GEP(llvm_void_ptr(Result,2), dstcomp), 0, 1, rt.basesize());
}
} else
llvm_zero_derivs (Result);
}
}
return true;
+47 -2
View File
@@ -38,6 +38,10 @@ using namespace OSL::pvt;
#include "runtimeoptimize.h"
#include <OSL/llvm_util.h>
// additional includes for creating global OptiX variables
#include "llvm/IR/Constants.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Module.h"
OSL_NAMESPACE_ENTER
@@ -85,7 +89,7 @@ public:
typedef std::map<std::string, llvm::Value*> AllocationMap;
void llvm_assign_initial_value (const Symbol& sym);
void llvm_assign_initial_value (const Symbol& sym, bool force = false);
llvm::LLVMContext &llvm_context () const { return ll.context(); }
AllocationMap &named_values () { return m_named_values; }
@@ -142,6 +146,10 @@ public:
return llvm_load_value (sym, deriv, NULL, component, cast);
}
/// Load the address of a global device-side string pointer, optionally
/// follow the pointer and cast the result to UINT64.
llvm::Value *llvm_load_device_string (const Symbol& sym, bool follow=true);
/// Legacy version
///
llvm::Value *loadLLVMValue (const Symbol& sym, int component=0,
@@ -211,6 +219,26 @@ public:
/// map, the symbol is alloca'd and placed in the map.
llvm::Value *getOrAllocateLLVMSymbol (const Symbol& sym);
/// Allocate a CUDA variable for the given OSL symbol and return a pointer
/// to the corresponding LLVM GlobalVariable, or return the pointer if it
/// has already been allocated.
llvm::Value *getOrAllocateCUDAVariable (const Symbol& sym);
/// Create a CUDA global variable and add it to the current Module
llvm::Value *addCUDAVariable (const std::string& name, int size,
int alignment, void* data,
const std::string& type="");
/// Create a CUDA variable, along with the extra semantic information needed
/// by OptiX.
llvm::Value *createOptixVariable (const std::string& name,
const std::string& type,
int size, void* data );
/// Create the extra semantic information needed for OptiX variables
void createOptixMetadata (const std::string& name,
const std::string& type, int size );
/// Retrieve an llvm::Value that is a pointer holding the start address
/// of the specified symbol. This always works for globals and params;
/// for stack variables (locals/temps) is succeeds only if the symbol is
@@ -229,7 +257,8 @@ public:
/// Implementaiton of Simple assignment. If arrayindex >= 0, in
/// designates a particular array index to assign.
bool llvm_assign_impl (Symbol &Result, Symbol &Src, int arrayindex = -1);
bool llvm_assign_impl (Symbol &Result, Symbol &Src, int arrayindex = -1,
int srcomp = -1, int dstcomp = -1);
/// Convert the name of a global (and its derivative index) into the
@@ -403,6 +432,12 @@ public:
shadingsys().m_stat_tex_calls_as_handles += 1;
}
/// Return the mapping from symbol names to GlobalVariables.
std::map<std::string,llvm::GlobalVariable*>& get_const_map() { return m_const_map; }
/// Return whether or not we are compiling for an OptiX-based renderer.
bool use_optix() { return m_use_optix; }
LLVM_Util ll;
private:
@@ -429,6 +464,16 @@ private:
llvm::PointerType *m_llvm_type_setup_closure_func;
int m_llvm_local_mem; // Amount of memory we use for locals
// A mapping from symbol names to llvm::GlobalVariables
std::map<std::string,llvm::GlobalVariable*> m_const_map;
// A mapping from canonical strings to string variable names, used to
// detect collisions that might occur due to using the string hash to
// create variable names.
std::map<std::string,std::string> m_varname_map;
bool m_use_optix; ///< Compile for OptiX?
friend class ShadingSystemImpl;
};
+1 -1
View File
@@ -386,7 +386,7 @@ DECL (osl_texture_set_subimagename, "xXs")
DECL (osl_texture_set_missingcolor_arena, "xXX")
DECL (osl_texture_set_missingcolor_alpha, "xXif")
DECL (osl_texture, "iXXXXffffffiXXXXXXX")
DECL (osl_texture3d, "iXXXXXXXXiXXXXXXXXX")
DECL (osl_texture3d, "iXXXXXXXiXXXXXXX")
DECL (osl_environment, "iXXXXXXXiXXXXXXX")
DECL (osl_get_textureinfo, "iXXXXiiiX")
+12 -3
View File
@@ -2345,7 +2345,7 @@ DECLFOLDER(constfold_getattribute)
ustring obj_name;
if (object_lookup)
obj_name = *(const ustring *)ObjectName.data();
if (! obj_name)
if (obj_name.empty())
return 0;
found = array_lookup
@@ -2539,9 +2539,18 @@ DECLFOLDER(constfold_texture)
#endif
CHECK_str (width, float, TypeDesc::FLOAT)
else CHECK_str (blur, float, TypeDesc::FLOAT)
else CHECK_str (wrap, ustring, TypeDesc::STRING)
else CHECK (firstchannel, int, TypeDesc::INT)
else CHECK (fill, float, TypeDesc::FLOAT)
else if ((name == Strings::wrap || name == Strings::swrap ||
name == Strings::twrap || name == Strings::rwrap)
&& value && valuetype == TypeDesc::STRING) {
// Special trick is needed for wrap modes because the input
// is a string but the field we're setting is an int enum.
OIIO::Tex::Wrap wrapmode = OIIO::Tex::decode_wrapmode (*(ustring *)value);
void* value = &wrapmode;
CHECK_str (wrap, int, TypeDesc::INT);
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
@@ -2666,7 +2675,7 @@ DECLFOLDER(constfold_pointcloud_search)
for (int i = 0; i < nattrs; ++i) {
// We had stashed names, data types, and destinations earlier.
// Retrieve them now to build a query.
if (! names[i])
if (names[i].empty())
continue;
void *const_data = NULL;
TypeDesc const_valtype = value_types[i];
+1 -1
View File
@@ -325,7 +325,7 @@ ShadingContext::osl_get_attribute (ShaderGlobals *sg, void *objdata,
bool ok;
for (auto& f : m_failed_attribs) {
if ((obj_name || f.objdata == objdata) &&
if ((!obj_name.empty() || f.objdata == objdata) &&
f.attr_name == attr_name && f.obj_name == obj_name &&
f.attr_type == attr_type && f.array_lookup == array_lookup &&
f.index == index && f.objdata) {
+5 -10
View File
@@ -36,12 +36,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <OpenImageIO/dassert.h>
#include <OpenImageIO/strutil.h>
#ifdef USE_EXTERNAL_PUGIXML
# include <pugixml.hpp>
#else
# include <OpenImageIO/pugixml.hpp>
#include <pugixml.hpp>
#ifdef USING_OIIO_PUGI
namespace pugi = OIIO::pugi;
#endif
#include "oslexec_pvt.h"
OSL_NAMESPACE_ENTER
@@ -49,12 +50,6 @@ OSL_NAMESPACE_ENTER
namespace pvt { // OSL::pvt
#ifndef USE_EXTERNAL_PUGIXML
namespace pugi = OIIO::pugi;
#endif
// Helper class to manage the dictionaries.
//
// Shaders are written as if they parse arbitrary things from whole
+3 -3
View File
@@ -28,13 +28,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <type_traits>
#include <OpenImageIO/dassert.h>
#include <OpenImageIO/unittest.h>
#include <OSL/oslconfig.h>
#include <OSL/dual.h>
#include <OSL/dual_vec.h>
#include <OpenImageIO/dassert.h>
#include <OpenImageIO/unittest.h>
using namespace OSL;
// Fix namespace problem with OIIO unit tests in older versions.
+35 -18
View File
@@ -246,7 +246,7 @@ ShaderInstance::parameters (const ParamValueList &params)
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) {
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))
@@ -313,13 +313,14 @@ ShaderInstance::parameters (const ParamValueList &params)
// data offsets to each parameter, we didn't know the length
// needed to allocate this param in its proper spot.
ASSERT (valuetype.arraylen > 0);
int nelements = valuetype.arraylen * valuetype.aggregate;
// Store the actual length in the shader instance parameter
// override info.
so->arraylen (valuetype.arraylen);
// 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.
int nelements = valuetype.arraylen * valuetype.aggregate;
if (paramtype.basetype == TypeDesc::FLOAT) {
so->dataoffset((int) m_fparams.size());
expand (m_fparams, nelements);
@@ -532,6 +533,27 @@ ShaderInstance::copy_code_from_master (ShaderGroup &group)
std::string
ConnectedParam::str (const ShaderInstance *inst)
{
const Symbol *s = inst->symbol(param);
return Strutil::format ("%s%s%s (%s)", s->name(),
arrayindex >= 0 ? Strutil::format("[%d]", arrayindex) : std::string(),
channel >= 0 ? Strutil::format("[%d]", channel) : std::string(),
type);
}
std::string
Connection::str (const ShaderGroup &group, const ShaderInstance *dstinst)
{
return Strutil::format ("%s -> %s", src.str (group[srclayer]),
dst.str (dstinst));
}
// Are the two vectors equivalent(a[i],b[i]) in each of their members?
template<class T>
inline bool
@@ -709,28 +731,23 @@ ShaderInstance::mergeable (const ShaderInstance &b, const ShaderGroup &g) const
ShaderGroup::ShaderGroup (string_view name)
: m_optimized(0), m_does_nothing(false),
m_llvm_groupdata_size(0), m_num_entry_layers(0),
m_llvm_compiled_version(NULL),
m_name(name), m_exec_repeat(1), m_raytype_queries(-1), m_raytypes_on(0), m_raytypes_off(0)
{
m_executions = 0;
m_stat_total_shading_time_ticks = 0;
m_id = ++(*(atomic_int *)&next_id);
if (name.size()) {
m_name = name;
} else {
// No name -- make one up using the unique
m_name = ustring::format ("unnamed_group_%d", m_id);
}
}
ShaderGroup::ShaderGroup (const ShaderGroup &g, string_view name)
: m_optimized(0), m_does_nothing(false),
m_llvm_groupdata_size(0), m_num_entry_layers(g.m_num_entry_layers),
m_llvm_compiled_version(NULL),
m_layers(g.m_layers),
m_name(name), m_exec_repeat(1), m_raytype_queries(-1), m_raytypes_on(0), m_raytypes_off(0)
: ShaderGroup(name) // delegate most of the work
{
m_executions = 0;
m_stat_total_shading_time_ticks = 0;
m_id = ++(*(atomic_int *)&next_id);
m_num_entry_layers = g.m_num_entry_layers;
m_layers = g.m_layers;
}
+104 -28
View File
@@ -157,10 +157,8 @@ BackendLLVM::llvm_call_layer (int layer, bool unconditional)
// insert point is now then_block
}
std::string name = Strutil::format ("%s_%d", parent->layername().c_str(),
parent->id());
// Mark the call as a fast call
llvm::Value *funccall = ll.call_function (name.c_str(), args, 2);
llvm::Value *funccall = ll.call_function (layer_function_name(group(), *parent).c_str(), args, 2);
if (!parent->entry_layer())
ll.mark_fast_func_call (funccall);
@@ -323,6 +321,8 @@ LLVMGEN (llvm_gen_printf)
std::string ourformat (oldfmt, format); // straddle the format
// Doctor it to fix mismatches between format and data
Symbol& sym (*rop.opargsym (op, arg));
ASSERT (! sym.typespec().is_structure_based());
TypeDesc simpletype (sym.typespec().simpletype());
int num_elements = simpletype.numelements();
int num_components = simpletype.aggregate;
@@ -358,12 +358,27 @@ LLVMGEN (llvm_gen_printf)
s += " ";
s += ourformat;
llvm::Value* loaded = rop.llvm_load_value (sym, 0, arrind, c);
llvm::Value* loaded = nullptr;
if (rop.use_optix() && simpletype.basetype == TypeDesc::STRING) {
// TODO: make this work with arrind
// In the OptiX case, we use the device-side string.
loaded = rop.llvm_load_device_string (sym);
}
else {
loaded = rop.llvm_load_value (sym, 0, arrind, c);
}
if (simpletype.basetype == TypeDesc::FLOAT) {
// C varargs convention upconverts float->double.
loaded = rop.ll.op_float_to_double(loaded);
}
if (simpletype.basetype == TypeDesc::INT && rop.use_optix()) {
// The printf supported by OptiX expects 8-byte arguments,
// so promote int to long long
loaded = rop.ll.op_int_to_longlong(loaded);
}
call_args.push_back (loaded);
}
}
@@ -374,6 +389,20 @@ LLVMGEN (llvm_gen_printf)
}
}
if (rop.use_optix() && arg > (format_arg + 2)) {
std::cerr << "WARNING: "
<< "OptiX only supports 0 or 1 printf arguments at this time. "
<< "Ignoring printf call in " << op.sourcefile() << std::endl;
return true;
}
// In OptiX, printf currently supports 0 or 1 arguments, and the signature
// requires 1 argument, so push a null pointer onto the call args if there
// is no argument.
if (rop.use_optix() && arg == format_arg + 1) {
call_args.push_back(rop.ll.void_ptr_null());
}
// Some ops prepend things
if (op.opname() == op_error || op.opname() == op_warning) {
std::string prefix = Strutil::format ("Shader %s [%s]: ",
@@ -383,7 +412,13 @@ LLVMGEN (llvm_gen_printf)
}
// Now go back and put the new format string in its place
call_args[new_format_slot] = rop.ll.constant (s.c_str());
if (! rop.use_optix()) {
call_args[new_format_slot] = rop.ll.constant (s.c_str());
}
else {
// In the OptiX case, we use the pointer to the device-side string
call_args[new_format_slot] = rop.llvm_load_device_string (format_sym);
}
// Construct the function name and call it.
std::string opname = std::string("osl_") + op.opname().string();
@@ -1336,9 +1371,24 @@ LLVMGEN (llvm_gen_aassign)
}
int num_components = Result.typespec().simpletype().aggregate;
// Allow float <=> int casting
TypeDesc cast;
if (num_components == 1 && !Result.typespec().is_closure() && !Src.typespec().is_closure() &&
(Result.typespec().is_int_based() || Result.typespec().is_float_based()) &&
(Src.typespec().is_int_based() || Src.typespec().is_float_based())) {
cast = Result.typespec().simpletype();
cast.arraylen = 0;
} else {
// Try to warn before llvm_fatal_error is called which provides little
// context as to what went wrong.
ASSERT (Result.typespec().simpletype().basetype ==
Src.typespec().simpletype().basetype);
}
for (int d = 0; d <= 2; ++d) {
for (int c = 0; c < num_components; ++c) {
llvm::Value *val = rop.loadLLVMValue (Src, c, d);
llvm::Value *val = rop.loadLLVMValue (Src, c, d, cast);
rop.llvm_store_value (val, Result, d, index, c);
}
if (! Result.has_derivs())
@@ -1720,6 +1770,27 @@ LLVMGEN (llvm_gen_compare_op)
llvm::Value* final_result = 0;
ustring opname = op.opname();
if (rop.use_optix() && A.typespec().is_string()) {
ASSERT (B.typespec().is_string() && "Only string-to-string comparison is supported");
llvm::Value* a = rop.llvm_load_device_string (A);
llvm::Value* b = rop.llvm_load_device_string (B);
if (opname == op_eq) {
final_result = rop.ll.op_eq (a, b);
} else if (opname == op_neq) {
final_result = rop.ll.op_ne (a, b);
} else {
// Don't know how to handle this.
ASSERT (0 && "OptiX only supports equality testing for strings");
}
ASSERT (final_result);
final_result = rop.ll.op_bool_to_int (final_result);
rop.storeLLVMValue (final_result, Result, 0, 0);
return true;
}
for (int i = 0; i < num_components; i++) {
// Get A&B component i -- note that these correctly handle mixed
// scalar/triple comparisons as well as int->float casts as needed.
@@ -2093,7 +2164,7 @@ llvm_gen_texture_options (BackendLLVM &rop, int opnum,
ustring name = *(ustring *)Name.data();
++a; // advance to next argument
if (! name) // skip empty string param name
if (name.empty()) // skip empty string param name
continue;
Symbol &Val (*rop.opargsym(op,a));
@@ -2202,7 +2273,7 @@ llvm_gen_texture_options (BackendLLVM &rop, int opnum,
if (name == Strings::subimage && valtype == TypeDesc::STRING) {
if (Val.is_constant()) {
ustring v = *(ustring *)Val.data();
if (! v && ! subimage_set) {
if (v.empty() && ! subimage_set) {
continue; // Ignore nulls unless they are overrides
}
}
@@ -2390,32 +2461,18 @@ LLVMGEN (llvm_gen_texture3d)
if (user_derivs) {
args.push_back (rop.llvm_void_ptr (*rop.opargsym (op, 3)));
args.push_back (rop.llvm_void_ptr (*rop.opargsym (op, 4)));
args.push_back (rop.llvm_void_ptr (*rop.opargsym (op, 5)));
} else {
// Auto derivs of P
args.push_back (rop.llvm_void_ptr (P, 1));
args.push_back (rop.llvm_void_ptr (P, 2));
// dPdz is correct for input P, zero for all else
if (&P == rop.inst()->symbol(rop.inst()->Psym())) {
args.push_back (rop.llvm_void_ptr (P, 3));
} else {
// zero for dPdz, for now
llvm::Value *fzero = rop.ll.constant (0.0f);
llvm::Value *vzero = rop.ll.op_alloca (rop.ll.type_triple());
for (int i = 0; i < 3; ++i)
rop.ll.op_store (fzero, rop.ll.GEP (vzero, 0, i));
args.push_back (rop.ll.void_ptr(vzero));
}
}
args.push_back (rop.ll.constant (nchans));
args.push_back (rop.ll.void_ptr (rop.llvm_void_ptr (Result, 0)));
args.push_back (rop.ll.void_ptr (rop.llvm_void_ptr (Result, 1)));
args.push_back (rop.ll.void_ptr (rop.llvm_void_ptr (Result, 2)));
args.push_back (rop.ll.void_ptr_null()); // no dresultdz for now
args.push_back (rop.ll.void_ptr (alpha ? alpha : rop.ll.void_ptr_null()));
args.push_back (rop.ll.void_ptr (dalphadx ? dalphadx : rop.ll.void_ptr_null()));
args.push_back (rop.ll.void_ptr (dalphady ? dalphady : rop.ll.void_ptr_null()));
args.push_back (rop.ll.void_ptr_null()); // No dalphadz for now
args.push_back (rop.ll.void_ptr (errormessage ? errormessage : rop.ll.void_ptr_null()));
rop.ll.call_function ("osl_texture3d", &args[0], (int)args.size());
rop.generated_texture_call (texture_handle != NULL);
@@ -2591,6 +2648,12 @@ llvm_gen_noise_options (BackendLLVM &rop, int opnum,
{
llvm::Value* opt = rop.ll.call_function ("osl_get_noise_options",
rop.sg_void_ptr());
// TODO: implement noise options in OptiX
if (rop.use_optix()) {
return opt;
}
Opcode &op (rop.inst()->ops()[opnum]);
for (int a = first_optional_arg; a < op.nargs(); ++a) {
Symbol &Name (*rop.opargsym(op,a));
@@ -2603,7 +2666,7 @@ llvm_gen_noise_options (BackendLLVM &rop, int opnum,
Symbol &Val (*rop.opargsym(op,a));
TypeDesc valtype = Val.typespec().simpletype ();
if (! name) // skip empty string param name
if (name.empty()) // skip empty string param name
continue;
if (name == Strings::anisotropic && Val.typespec().is_int()) {
@@ -2694,7 +2757,7 @@ LLVMGEN (llvm_gen_noise)
derivs &= Result.has_derivs(); // ignore derivs if result doesn't need
bool pass_name = false, pass_sg = false, pass_options = false;
if (! name) {
if (name.empty()) {
// name is not a constant
name = periodic ? Strings::genericpnoise : Strings::genericnoise;
pass_name = true;
@@ -2758,8 +2821,14 @@ LLVMGEN (llvm_gen_noise)
std::string funcname = "osl_" + name.string() + "_" + arg_typecode(&Result,derivs);
std::vector<llvm::Value *> args;
if (pass_name)
args.push_back (rop.llvm_load_value(*Name));
if (pass_name) {
if (! rop.use_optix()) {
args.push_back (rop.llvm_load_value(*Name));
}
else {
args.push_back (rop.llvm_load_device_string (*Name));
}
}
llvm::Value *tmpresult = NULL;
// triple return, or float return with derivs, passes result pointer
if (outdim == 3 || derivs) {
@@ -3260,8 +3329,15 @@ LLVMGEN (llvm_gen_closure)
DASSERT(p.offset + p.field_size <= clentry->struct_size);
Symbol &sym = *rop.opargsym (op, carg + 2 + weighted);
TypeDesc t = sym.typespec().simpletype();
if (!sym.typespec().is_closure_array() && !sym.typespec().is_structure()
&& equivalent(t,p.type)) {
if (rop.use_optix() && sym.typespec().is_string()) {
llvm::Value* dst = rop.ll.offset_ptr (mem_void_ptr, p.offset);
llvm::Value* src = rop.llvm_load_device_string (sym);
rop.ll.op_memcpy (dst, src, (int)p.type.size(),
4 /* use 4 byte alignment for now */);
}
else if (!sym.typespec().is_closure_array() && !sym.typespec().is_structure()
&& equivalent(t,p.type)) {
llvm::Value* dst = rop.ll.offset_ptr (mem_void_ptr, p.offset);
llvm::Value* src = rop.llvm_void_ptr (sym);
rop.ll.op_memcpy (dst, src, (int)p.type.size(),
+197 -41
View File
@@ -27,7 +27,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cmath>
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <OpenImageIO/timer.h>
#include <OpenImageIO/sysutil.h>
@@ -111,6 +114,9 @@ Schematically, we want to create code that resembles the following:
extern int osl_llvm_compiled_ops_size;
extern char osl_llvm_compiled_ops_block[];
extern int osl_llvm_compiled_ops_cuda_size;
extern char osl_llvm_compiled_ops_cuda_block[];
using namespace OSL::pvt;
OSL_NAMESPACE_ENTER
@@ -267,7 +273,13 @@ BackendLLVM::llvm_type_groupdata ()
++order;
for (int i = 0; i < nuserdata; ++i) {
TypeDesc type = types[i];
int n = type.numelements() * 3; // always make deriv room
// NB: Userdata derivs are not currently supported in OptiX, since
// making room for them in the GroupData struct can result in a
// large per-thread memory allocation, which could negatively
// impact performance.
int n = (! use_optix())
? type.numelements() * 3 // make room for derivs by default
: type.numelements();
type.arraylen = n;
fields.push_back (llvm_type (type));
// Alignment
@@ -364,12 +376,12 @@ BackendLLVM::llvm_type_closure_component_ptr ()
void
BackendLLVM::llvm_assign_initial_value (const Symbol& sym)
BackendLLVM::llvm_assign_initial_value (const Symbol& sym, bool force)
{
// Don't write over connections! Connection values are written into
// our layer when the earlier layer is run, as part of its code. So
// we just don't need to initialize it here at all.
if (sym.valuesource() == Symbol::ConnectedVal &&
if (!force && sym.valuesource() == Symbol::ConnectedVal &&
!sym.typespec().is_closure_based())
return;
if (sym.typespec().is_closure_based() && sym.symtype() == SymTypeGlobal)
@@ -440,9 +452,24 @@ BackendLLVM::llvm_assign_initial_value (const Symbol& sym)
}
}
ASSERT (userdata_index >= 0);
std::vector<llvm::Value*> args;
args.push_back (sg_void_ptr());
args.push_back (ll.constant (symname));
llvm::Value* name_arg = NULL;
if (use_optix()) {
// In the OptiX case, we need to get the pointer to the string
// constant for the symbol name.
ustring arg_name = ustring::format ("$symname_%s_%d", symname, sym.layer());
Symbol symname_const (arg_name, TypeDesc::TypeString, SymTypeConst);
symname_const.data (&symname);
name_arg = llvm_load_device_string (symname_const);
} else {
name_arg = ll.constant (symname);
}
args.push_back (name_arg);
args.push_back (ll.constant (type));
args.push_back (ll.constant ((int) group().m_userdata_derivs[userdata_index]));
args.push_back (groupdata_field_ptr (2 + userdata_index)); // userdata data ptr
@@ -458,11 +485,11 @@ BackendLLVM::llvm_assign_initial_value (const Symbol& sym)
// check for NaN/Inf for float-based types
int ncomps = type.numelements() * type.aggregate;
llvm::Value *args[] = { ll.constant(ncomps), llvm_void_ptr(sym),
ll.constant((int)sym.has_derivs()), sg_void_ptr(),
ll.constant(ustring(inst()->shadername())),
ll.constant(0), ll.constant(sym.name()),
ll.constant(0), ll.constant(ncomps),
ll.constant("<get_userdata>")
ll.constant((int)sym.has_derivs()), sg_void_ptr(),
ll.constant(ustring(inst()->shadername())),
ll.constant(0), ll.constant(sym.name()),
ll.constant(0), ll.constant(ncomps),
ll.constant("<get_userdata>")
};
ll.call_function ("osl_naninf_check", args, 10);
}
@@ -478,13 +505,36 @@ BackendLLVM::llvm_assign_initial_value (const Symbol& sym)
if (sym.has_init_ops() && sym.valuesource() == Symbol::DefaultVal) {
// Handle init ops.
build_llvm_code (sym.initbegin(), sym.initend());
} else if (! sym.lockgeom() && ! sym.typespec().is_closure()) {
} else if (! sym.lockgeom() && ! sym.typespec().is_closure() &&
! use_optix()) {
// geometrically-varying param; memcpy its default value
TypeDesc t = sym.typespec().simpletype();
ll.op_memcpy (llvm_void_ptr (sym), ll.constant_ptr (sym.data()),
t.size(), t.basesize() /*align*/);
if (sym.has_derivs())
llvm_zero_derivs (sym);
} else if (use_optix() && ! sym.typespec().is_string()) {
// If the call to osl_bind_interpolated_param returns 0, the default
// value needs to be loaded from a corresponding OptiX variable, which
// we are creating here.
ustring var_name = ustring::format ("%s_%s_%s_%d", sym.name(),
inst()->layername(), group().name(), group().id());
// TODO: Make sure this works with string variables
llvm::Value* ud_var = createOptixVariable (var_name.string(),
sym.typespec().simpletype().c_str(),
sym.size(),
sym.data());
// memcpy the value from the OptiX variable into the GroupData struct
llvm::Value* src = ll.ptr_cast (ll.GEP (ud_var, 0), ll.type_void_ptr());
llvm::Value* dst = llvm_void_ptr (sym);
TypeDesc t = sym.typespec().simpletype();
ll.op_memcpy (dst, src, t.size(), t.basesize());
} else if (use_optix() && sym.typespec().is_string()) {
llvm::Value* src = llvm_load_device_string (sym);
ll.op_memcpy (llvm_void_ptr (sym), src, 8, 4);
} else {
// Use default value
int num_components = sym.typespec().simpletype().aggregate;
@@ -712,7 +762,9 @@ BackendLLVM::build_llvm_init ()
ll.op_memset (ll.void_ptr(layer_run_ref(0)), 0, sz, 4 /*align*/);
}
int num_userdata = (int) group().m_userdata_names.size();
if (num_userdata) {
if (num_userdata && ! use_optix()) {
// NB: we don't need these flags in the OptiX case because userdata is
// accessed through rtVariables, which are guaranteed to be initialized
int sz = (num_userdata + 3) & (~3); // round up to 32 bits
ll.op_memset (ll.void_ptr(userdata_initialized_ref(0)), 0, sz, 4 /*align*/);
}
@@ -761,8 +813,7 @@ 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());
std::string unique_layer_name = layer_function_name();
bool is_entry_layer = group().is_entry_layer(layer());
ll.current_function (
ll.make_function (unique_layer_name,
@@ -896,22 +947,66 @@ BackendLLVM::build_llvm_instance (bool groupentry)
if (llvm_has_exit_instance_block())
ll.op_branch (m_exit_instance_block); // also sets insert point
// Track all symbols who needed 'partial' initialization
std::unordered_set<Symbol*> initedsyms;
// 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) {
for (int c = 0, Nc = child->nconnections(); c < Nc; ++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");
ASSERT (con.src.arrayindex == -1 && con.dst.arrayindex == -1 &&
"no support for individual array element connections");
// Validate unsupported connection vecSrc -> vecDst[j]
ASSERT ((con.dst.channel == -1 ||
con.src.type.aggregate() == TypeDesc::SCALAR ||
con.src.channel != -1) &&
"no support for vector -> vector[i] connections");
Symbol *srcsym (inst()->symbol (con.src.param));
Symbol *dstsym (child->symbol (con.dst.param));
// Check remining connections to see if any channels of this
// aggregate need to be initialize.
if (con.dst.channel != -1 && initedsyms.count(dstsym) == 0) {
initedsyms.insert(dstsym);
std::bitset<32> inited(0); // Only need to be 16 (matrix4)
assert(dstsym->typespec().aggregate() <= inited.size());
unsigned ninit = dstsym->typespec().aggregate() - 1;
for (int rc = c+1; rc < Nc && ninit; ++rc) {
const Connection &next (child->connection (rc));
if (next.srclayer == this->layer()) {
// Allow redundant/overwriting connections, i.e:
// 1. connect layer.value[i] connect layer.value[j]
// 2. connect layer.value connect layer.value
if (child->symbol (next.dst.param) == dstsym) {
if (next.dst.channel != -1) {
assert(next.dst.channel < (int)inited.size());
if (!inited[next.dst.channel]) {
inited[next.dst.channel] = true;
--ninit;
}
} else
ninit = 0;
}
}
}
if (ninit) {
// FIXME: Init only components that are not connected
llvm_assign_initial_value (*dstsym, true);
}
}
// llvm_run_connected_layers tracks layers that have been run,
// so no need to do it here as well
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_assign_impl (*dstsym, *srcsym, -1,
con.src.channel, con.dst.channel);
}
}
}
@@ -947,7 +1042,10 @@ BackendLLVM::initialize_llvm_group ()
m_llvm_type_closure_component = NULL;
initialize_llvm_helper_function_map();
ll.InstallLazyFunctionCreator (helper_function_lookup);
// Skipping this in the non-JIT OptiX case suppresses an LLVM warning
if (! use_optix())
ll.InstallLazyFunctionCreator (helper_function_lookup);
for (HelperFuncMap::iterator i = llvm_helper_function_map.begin(),
e = llvm_helper_function_map.end(); i != e; ++i) {
@@ -971,7 +1069,10 @@ BackendLLVM::initialize_llvm_group ()
types += advance;
}
llvm::Function *f = ll.make_function (funcname, false, llvm_type(rettype), params, varargs);
ll.add_function_mapping (f, (void *)i->second.function);
// Skipping this in the non-JIT OptiX case suppresses an LLVM warning
if (! use_optix())
ll.add_function_mapping (f, (void *)i->second.function);
}
// Needed for closure setup
@@ -1018,16 +1119,27 @@ BackendLLVM::run ()
#ifdef OSL_LLVM_NO_BITCODE
ll.module (ll.new_module ("llvm_ops"));
#else
ll.module (ll.module_from_bitcode (osl_llvm_compiled_ops_block,
osl_llvm_compiled_ops_size,
"llvm_ops", &err));
if (! use_optix()) {
ll.module (ll.module_from_bitcode (osl_llvm_compiled_ops_block,
osl_llvm_compiled_ops_size,
"llvm_ops", &err));
} else {
#ifdef OSL_LLVM_CUDA_BITCODE
ll.module (ll.module_from_bitcode (osl_llvm_compiled_ops_cuda_block,
osl_llvm_compiled_ops_cuda_size,
"llvm_ops", &err));
#else
ASSERT (0 && "Must generate LLVM CUDA bitcode for OptiX");
#endif
}
if (err.length())
shadingcontext()->error ("ParseBitcodeFile returned '%s'\n", err.c_str());
ASSERT (ll.module());
#endif
// Create the ExecutionEngine
if (! ll.make_jit_execengine (&err)) {
// Create the ExecutionEngine. We don't create an ExecutionEngine in the
// OptiX case, because we are using the NVPTX backend and not MCJIT
if (! use_optix() && ! ll.make_jit_execengine (&err)) {
shadingcontext()->error ("Failed to create engine: %s\n", err.c_str());
ASSERT (0);
return;
@@ -1103,6 +1215,22 @@ BackendLLVM::run ()
}
ll.internalize_module_functions ("osl_", external_function_names, entry_function_names);
// Debug code to dump the pre-optimized bitcode to a file
if (llvm_debug() >= 2 || shadingsys().llvm_output_bitcode()) {
// Make a safe group name that doesn't have "/" in it! Also beware
// filename length limits.
std::string safegroup = Strutil::replace (group().name(), "/", ".", true);
if (safegroup.size() > 235)
safegroup = Strutil::format ("TRUNC_%s_%d", safegroup.substr(safegroup.size()-235), group().id());
std::string name = Strutil::format ("%s.ll", safegroup);
std::ofstream out (name, std::ios_base::out | std::ios_base::trunc);
if (out.good()) {
out << ll.bitcode_string (ll.module());
} else {
shadingcontext()->error ("Could not write to '%s'", name);
}
}
// Optimize the LLVM IR unless it's a do-nothing group.
if (! group().does_nothing())
ll.do_optimize();
@@ -1116,25 +1244,53 @@ BackendLLVM::run ()
std::cout.flush();
}
// Debug code to dump the resulting bitcode to a file
if (llvm_debug() >= 2) {
std::string name = Strutil::format ("%s_%d.bc", inst()->layername(),
inst()->id());
ll.write_bitcode_file (name.c_str());
// Debug code to dump the post-optimized bitcode to a file
if (llvm_debug() >= 2 || shadingsys().llvm_output_bitcode()) {
// Make a safe group name that doesn't have "/" in it! Also beware
// filename length limits.
std::string safegroup = Strutil::replace (group().name(), "/", ".", true);
if (safegroup.size() > 235)
safegroup = Strutil::format ("TRUNC_%s_%d", safegroup.substr(safegroup.size()-235), group().id());
std::string name = Strutil::format ("%s_opt.ll", safegroup);
std::ofstream out (name, std::ios_base::out | std::ios_base::trunc);
if (out.good()) {
out << ll.bitcode_string (ll.module());
} else {
shadingcontext()->error ("Could not write to '%s'", name);
}
}
// Force the JIT to happen now and retrieve the JITed function pointers
// for the initialization and all public entry points.
group().llvm_compiled_init ((RunLLVMGroupFunc) ll.getPointerToFunction(init_func));
for (int layer = 0; layer < nlayers; ++layer) {
llvm::Function* f = funcs[layer];
if (f && group().is_entry_layer (layer))
group().llvm_compiled_layer (layer, (RunLLVMGroupFunc) ll.getPointerToFunction(f));
if (use_optix()) {
// Create an llvm::Module from the renderer-supplied library bitcode
std::vector<char>& bitcode = shadingsys().m_lib_bitcode;
ASSERT (bitcode.size() && "Library bitcode is empty");
// TODO: Is it really necessary to build this Module for every ShaderGroup
llvm::Module* lib_module =
ll.module_from_bitcode (static_cast<const char*>(bitcode.data()),
bitcode.size(), "cuda_lib");
std::string name = Strutil::format ("%s_%d", group().name(), group().id());
ll.ptx_compile_group (lib_module, name, group().m_llvm_ptx_compiled_version);
if (group().m_llvm_ptx_compiled_version.empty()) {
ASSERT (0 && "Unable to generate PTX");
}
}
else {
// Force the JIT to happen now and retrieve the JITed function pointers
// for the initialization and all public entry points.
group().llvm_compiled_init ((RunLLVMGroupFunc) ll.getPointerToFunction(init_func));
for (int layer = 0; layer < nlayers; ++layer) {
llvm::Function* f = funcs[layer];
if (f && group().is_entry_layer (layer))
group().llvm_compiled_layer (layer, (RunLLVMGroupFunc) ll.getPointerToFunction(f));
}
if (group().num_entry_layers())
group().llvm_compiled_version (NULL);
else
group().llvm_compiled_version (group().llvm_compiled_layer(nlayers-1));
}
if (group().num_entry_layers())
group().llvm_compiled_version (NULL);
else
group().llvm_compiled_version (group().llvm_compiled_layer(nlayers-1));
// Remove the IR for the group layer functions, we've already JITed it
// and will never need the IR again. This saves memory, and also saves
+13 -8
View File
@@ -147,7 +147,11 @@ void * __dso_handle = 0; // necessary to avoid linkage issues in bitcode
#ifndef OSL_SHADEOP
#define OSL_SHADEOP extern "C" OSL_LLVM_EXPORT
# ifdef __CUDACC__
# define OSL_SHADEOP extern "C" __device__ OSL_LLVM_EXPORT
# else
# define OSL_SHADEOP extern "C" OSL_LLVM_EXPORT
# endif
#endif
@@ -449,8 +453,8 @@ MAKE_UNARY_PERCOMPONENT_OP (exp2 , OIIO::fast_exp2 , fast_exp2)
MAKE_UNARY_PERCOMPONENT_OP (expm1 , OIIO::fast_expm1 , fast_expm1)
MAKE_BINARY_PERCOMPONENT_OP (pow , OIIO::fast_safe_pow , fast_safe_pow)
MAKE_BINARY_PERCOMPONENT_VF_OP (pow , OIIO::fast_safe_pow , fast_safe_pow)
MAKE_UNARY_PERCOMPONENT_OP (erf , OIIO::fast_erf , erf)
MAKE_UNARY_PERCOMPONENT_OP (erfc , OIIO::fast_erfc , erfc)
MAKE_UNARY_PERCOMPONENT_OP (erf , OIIO::fast_erf , fast_erf)
MAKE_UNARY_PERCOMPONENT_OP (erfc , OIIO::fast_erfc , fast_erfc)
#else
MAKE_UNARY_PERCOMPONENT_OP (log , OIIO::safe_log , safe_log)
MAKE_UNARY_PERCOMPONENT_OP (log2 , OIIO::safe_log2 , safe_log2)
@@ -463,6 +467,7 @@ MAKE_BINARY_PERCOMPONENT_VF_OP (pow , OIIO::safe_pow , safe_pow)
MAKE_UNARY_PERCOMPONENT_OP (erf , erff , erf)
MAKE_UNARY_PERCOMPONENT_OP (erfc , erfcf , erfc)
#endif
MAKE_UNARY_PERCOMPONENT_OP (sqrt , OIIO::safe_sqrt , sqrt)
MAKE_UNARY_PERCOMPONENT_OP (inversesqrt, OIIO::safe_inversesqrt, inversesqrt)
@@ -517,7 +522,7 @@ OSL_SHADEOP int osl_isfinite_if (float f) { return OIIO::isfinite (f); }
OSL_SHADEOP int osl_abs_ii (int x) { return abs(x); }
OSL_SHADEOP int osl_fabs_ii (int x) { return abs(x); }
inline Dual2<float> fabsf (const Dual2<float> &x) {
OSL_HOSTDEVICE inline Dual2<float> fabsf (const Dual2<float> &x) {
return x.val() >= 0 ? x : -x;
}
@@ -528,11 +533,11 @@ OSL_SHADEOP int osl_safe_mod_iii (int a, int b) {
return (b != 0) ? (a % b) : 0;
}
inline float safe_fmod (float a, float b) {
OSL_HOSTDEVICE inline float safe_fmod (float a, float b) {
return (b != 0.0f) ? std::fmod (a,b) : 0.0f;
}
inline Dual2<float> safe_fmod (const Dual2<float> &a, const Dual2<float> &b) {
OSL_HOSTDEVICE inline Dual2<float> safe_fmod (const Dual2<float> &a, const Dual2<float> &b) {
return Dual2<float> (safe_fmod (a.val(), b.val()), a.dx(), a.dy());
}
@@ -725,7 +730,7 @@ osl_normalize_dvdv (void *result, void *a)
inline Vec3 calculatenormal(void *P_, bool flipHandedness)
OSL_HOSTDEVICE inline Vec3 calculatenormal(void *P_, bool flipHandedness)
{
Dual2<Vec3> &tmpP (DVEC(P_));
if (flipHandedness)
@@ -750,7 +755,7 @@ OSL_SHADEOP float osl_area(void *P_)
inline float filter_width(float dx, float dy)
OSL_HOSTDEVICE inline float filter_width(float dx, float dy)
{
return sqrtf(dx*dx + dy*dy);
}
+241 -307
View File
@@ -28,20 +28,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory>
#include <cinttypes>
#include <OpenImageIO/thread.h>
#include <boost/thread/tss.hpp> /* for thread_specific_ptr */
#include <OSL/oslconfig.h>
#include <OSL/llvm_util.h>
#if OSL_LLVM_VERSION < 35 || OSL_CPLUSPLUS_VERSION < 11
#error "C++11 and LLVM >= 3.5 are required"
#if OSL_LLVM_VERSION < 40
#error "LLVM minimum version required for OSL is 4.0"
#endif
// Use MCJIT for LLVM 3.6 and beyind, old JIT for earlier
#define USE_MCJIT (OSL_LLVM_VERSION >= 36)
#define USE_OLD_JIT (OSL_LLVM_VERSION < 36)
#include <llvm/IR/Constants.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Instructions.h>
@@ -56,56 +53,72 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Support/TargetRegistry.h>
#if OSL_LLVM_VERSION < 40
# include <llvm/Bitcode/ReaderWriter.h>
#else
# include <llvm/Bitcode/BitcodeReader.h>
# include <llvm/Bitcode/BitcodeWriter.h>
#endif
#include <llvm/Bitcode/BitcodeReader.h>
#include <llvm/Bitcode/BitcodeWriter.h>
#include <llvm/Support/ManagedStatic.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/ExecutionEngine/GenericValue.h>
#if USE_MCJIT
# include <llvm/ExecutionEngine/MCJIT.h>
#endif
#if USE_OLD_JIT
# include <llvm/ExecutionEngine/JIT.h>
# include <llvm/ExecutionEngine/JITMemoryManager.h>
#endif
#include <llvm/ExecutionEngine/JITEventListener.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/PrettyStackTrace.h>
#include <llvm/IR/Verifier.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/Target/TargetOptions.h>
#include <llvm/Transforms/Scalar.h>
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/Utils/UnifyFunctionExitNodes.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
#if OSL_LLVM_VERSION >= 36
# include <llvm/ExecutionEngine/SectionMemoryManager.h>
#endif
#if OSL_LLVM_VERSION >= 39
# include <llvm/Transforms/Scalar/GVN.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/Transforms/Scalar/GVN.h>
#if OSL_LLVM_VERSION >= 70
#include <llvm/Transforms/Utils.h>
#include <llvm/Transforms/InstCombine/InstCombine.h>
#endif
// additional includes for PTX generation
#include <llvm/Transforms/Utils/SymbolRewriter.h>
#include <llvm/Transforms/Utils/Cloning.h>
#include <llvm/Analysis/TargetTransformInfo.h>
OSL_NAMESPACE_ENTER
namespace pvt {
#if USE_OLD_JIT
typedef llvm::JITMemoryManager LLVMMemoryManager;
#else
typedef llvm::SectionMemoryManager LLVMMemoryManager;
#endif
typedef llvm::SectionMemoryManager LLVMMemoryManager;
#if OSL_LLVM_VERSION < 40
typedef std::error_code LLVMErr;
#else
typedef llvm::Error LLVMErr;
#endif
typedef llvm::Error LLVMErr;
namespace {
#if OSL_LLVM_VERSION >= 60
// NOTE: This is a COPY of something internal to LLVM, but since we destroy our LLVMMemoryManager
// via global variables we can't rely on the LLVM copy sticking around.
// Because of this, the variable must be declared _before_ jitmm_hold so that the object stays
// valid until after we have destroyed all our memory managers.
struct DefaultMMapper final : public llvm::SectionMemoryManager::MemoryMapper {
llvm::sys::MemoryBlock
allocateMappedMemory(llvm::SectionMemoryManager::AllocationPurpose Purpose,
size_t NumBytes, const llvm::sys::MemoryBlock *const NearBlock,
unsigned Flags, std::error_code &EC) override {
return llvm::sys::Memory::allocateMappedMemory(NumBytes, NearBlock, Flags, EC);
}
std::error_code protectMappedMemory(const llvm::sys::MemoryBlock &Block,
unsigned Flags) override {
return llvm::sys::Memory::protectMappedMemory(Block, Flags);
}
std::error_code releaseMappedMemory(llvm::sys::MemoryBlock &M) override {
return llvm::sys::Memory::releaseMappedMemory(M);
}
};
static DefaultMMapper llvm_default_mapper;
#endif
static OIIO::spin_mutex llvm_global_mutex;
static bool setup_done = false;
static boost::thread_specific_ptr<LLVM_Util::PerThreadInfo> perthread_infos;
@@ -147,15 +160,6 @@ LLVM_Util::total_jit_memory_held ()
{
size_t jitmem = 0;
OIIO::spin_lock lock (llvm_global_mutex);
#if USE_OLD_JIT
for (size_t i = 0; i < jitmm_hold.size(); ++i) {
LLVMMemoryManager *mm = jitmm_hold[i].get();
if (mm)
jitmem += mm->GetDefaultCodeSlabSize() * mm->GetNumCodeSlabs()
+ mm->GetDefaultDataSlabSize() * mm->GetNumDataSlabs()
+ mm->GetDefaultStubSlabSize() * mm->GetNumStubSlabs();
}
#endif
return jitmem;
}
@@ -169,69 +173,12 @@ protected:
LLVMMemoryManager *mm; // the real one
public:
#if USE_OLD_JIT // llvm::JITMemoryManager
MemoryManager(LLVMMemoryManager *realmm) : mm(realmm) { HasGOT = realmm->isManagingGOT(); }
virtual void setMemoryWritable() { mm->setMemoryWritable(); }
virtual void setMemoryExecutable() { mm->setMemoryExecutable(); }
virtual void setPoisonMemory(bool poison) { mm->setPoisonMemory(poison); }
virtual void AllocateGOT() { ASSERT(HasGOT == false); ASSERT(HasGOT == mm->isManagingGOT()); mm->AllocateGOT(); HasGOT = true; ASSERT(HasGOT == mm->isManagingGOT()); }
virtual uint8_t *getGOTBase() const { return mm->getGOTBase(); }
virtual uint8_t *startFunctionBody(const llvm::Function *F,
uintptr_t &ActualSize) {
return mm->startFunctionBody (F, ActualSize);
}
virtual uint8_t *allocateStub(const llvm::GlobalValue* F, unsigned StubSize,
unsigned Alignment) {
return mm->allocateStub (F, StubSize, Alignment);
}
virtual void endFunctionBody(const llvm::Function *F,
uint8_t *FunctionStart, uint8_t *FunctionEnd) {
mm->endFunctionBody (F, FunctionStart, FunctionEnd);
}
virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
return mm->allocateSpace (Size, Alignment);
}
virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) {
return mm->allocateGlobal (Size, Alignment);
}
virtual void deallocateFunctionBody(void *Body) {
// DON'T DEALLOCATE mm->deallocateFunctionBody (Body);
}
virtual bool CheckInvariants(std::string &s) {
return mm->CheckInvariants(s);
}
virtual size_t GetDefaultCodeSlabSize() {
return mm->GetDefaultCodeSlabSize();
}
virtual size_t GetDefaultDataSlabSize() {
return mm->GetDefaultDataSlabSize();
}
virtual size_t GetDefaultStubSlabSize() {
return mm->GetDefaultStubSlabSize();
}
virtual unsigned GetNumCodeSlabs() { return mm->GetNumCodeSlabs(); }
virtual unsigned GetNumDataSlabs() { return mm->GetNumDataSlabs(); }
virtual unsigned GetNumStubSlabs() { return mm->GetNumStubSlabs(); }
virtual void notifyObjectLoaded(llvm::ExecutionEngine *EE, const llvm::ObjectImage *oi) {
mm->notifyObjectLoaded (EE, oi);
}
#else // MCJITMemoryManager
MemoryManager(LLVMMemoryManager *realmm) : mm(realmm) {}
virtual void notifyObjectLoaded(llvm::ExecutionEngine *EE, const llvm::object::ObjectFile &oi) {
mm->notifyObjectLoaded (EE, oi);
}
#if OSL_LLVM_VERSION <= 37
virtual void reserveAllocationSpace(
uintptr_t CodeSize, uintptr_t DataSizeRO, uintptr_t DataSizeRW) {
return mm->reserveAllocationSpace(CodeSize, DataSizeRO, DataSizeRW);
}
#else
virtual void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
uintptr_t RODataSize,
uint32_t RODataAlign,
@@ -239,7 +186,6 @@ public:
uint32_t RWDataAlign) {
return mm->reserveAllocationSpace(CodeSize, CodeAlign, RODataSize, RODataAlign, RWDataSize, RWDataAlign);
}
#endif
virtual bool needsToReserveAllocationSpace() {
return mm->needsToReserveAllocationSpace();
@@ -248,8 +194,6 @@ public:
virtual void invalidateInstructionCache() {
mm->invalidateInstructionCache();
}
#endif
// Common
virtual ~MemoryManager() {}
@@ -271,14 +215,16 @@ public:
virtual void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {
mm->registerEHFrames (Addr, LoadAddr, Size);
}
virtual void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {
#if OSL_LLVM_VERSION < 50
virtual void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {
mm->deregisterEHFrames(Addr, LoadAddr, Size);
#else
// TODO: verify this is correct
mm->deregisterEHFrames();
#endif
}
#else
virtual void deregisterEHFrames() {
mm->deregisterEHFrames();
}
#endif
virtual uint64_t getSymbolAddress(const std::string &Name) {
return mm->getSymbolAddress (Name);
}
@@ -289,15 +235,6 @@ public:
#if OSL_LLVM_VERSION <= 38
class LLVM_Util::IRBuilder : public llvm::IRBuilder<true,llvm::ConstantFolder,
llvm::IRBuilderDefaultInserter<true> > {
typedef llvm::IRBuilder<true, llvm::ConstantFolder,
llvm::IRBuilderDefaultInserter<true> > Base;
public:
IRBuilder(llvm::BasicBlock *TheBB) : Base(TheBB) {}
};
#else
class LLVM_Util::IRBuilder : public llvm::IRBuilder<llvm::ConstantFolder,
llvm::IRBuilderDefaultInserter> {
typedef llvm::IRBuilder<llvm::ConstantFolder,
@@ -305,7 +242,6 @@ class LLVM_Util::IRBuilder : public llvm::IRBuilder<llvm::ConstantFolder,
public:
IRBuilder(llvm::BasicBlock *TheBB) : Base(TheBB) {}
};
#endif
@@ -327,20 +263,16 @@ LLVM_Util::LLVM_Util (int debuglevel)
m_thread->llvm_context = new llvm::LLVMContext();
if (! m_thread->llvm_jitmm) {
#if USE_OLD_JIT
m_thread->llvm_jitmm = llvm::JITMemoryManager::CreateDefaultMemManager();
#if OSL_LLVM_VERSION >= 60
m_thread->llvm_jitmm = new LLVMMemoryManager(&llvm_default_mapper);
#else
m_thread->llvm_jitmm = new LLVMMemoryManager;
m_thread->llvm_jitmm = new LLVMMemoryManager();
#endif
ASSERT (m_thread->llvm_jitmm);
jitmm_hold.push_back (std::shared_ptr<LLVMMemoryManager>(m_thread->llvm_jitmm));
jitmm_hold.emplace_back (m_thread->llvm_jitmm);
}
#if USE_OLD_JIT
m_llvm_jitmm = new MemoryManager(m_thread->llvm_jitmm);
#else
// Hold the REAL manager and use it as an argument later
m_llvm_jitmm = reinterpret_cast<MemoryManager*>(m_thread->llvm_jitmm);
#endif
m_llvm_jitmm = m_thread->llvm_jitmm;
}
m_llvm_context = m_thread->llvm_context;
@@ -395,31 +327,17 @@ LLVM_Util::SetupLLVM ()
return;
// Some global LLVM initialization for the first thread that
// gets here.
#if USE_MCJIT
LLVMInitializeNativeTarget();
LLVMInitializeNativeDisassembler();
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllDisassemblers();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();
LLVMLinkInMCJIT();
#else
llvm::InitializeNativeTarget();
#endif
if (debug()) {
#if OSL_LLVM_VERSION <= 36
# define OSL_TGT_DEF(t) t->
for (llvm::TargetRegistry::iterator t = llvm::TargetRegistry::begin();
t != llvm::TargetRegistry::end(); ++t)
#else
# define OSL_TGT_DEF(t) t.
for (auto t : llvm::TargetRegistry::targets())
#endif
{
std::cout << "Target: '" << OSL_TGT_DEF(t)getName() << "' "
<< OSL_TGT_DEF(t)getShortDescription() << "\n";
}
#undef OSL_TGT_DEF
std::cout << "Target: '" << t.getName() << "' "
<< t.getShortDescription() << "\n";
std::cout << "\n";
}
@@ -436,15 +354,6 @@ LLVM_Util::new_module (const char *id)
#if OSL_LLVM_VERSION < 40
inline bool error_string (const std::error_code &err, std::string *str) {
if (err) {
if (str) *str = err.message();
return true;
}
return false;
}
#else
inline bool error_string (llvm::Error err, std::string *str) {
if (err) {
if (str) {
@@ -455,7 +364,6 @@ inline bool error_string (llvm::Error err, std::string *str) {
}
return false;
}
#endif
@@ -466,32 +374,8 @@ LLVM_Util::module_from_bitcode (const char *bitcode, size_t size,
if (err)
err->clear();
#if OSL_LLVM_VERSION <= 35 /* Old JIT vvvvvvvvvvvvvvvvvvvvvvvvvvvv */
llvm::MemoryBuffer* buf =
llvm::MemoryBuffer::getMemBuffer (llvm::StringRef(bitcode, size), name);
// Create a lazily deserialized IR module
// This can only be done for old JIT
llvm::Module *m = llvm::getLazyBitcodeModule (buf, context()).get();
// don't delete buf, the module has taken ownership of it
#if 0
// Debugging: print all functions in the module
for (llvm::Module::iterator i = m->begin(); i != m->end(); ++i)
std::cout << " found " << i->getName().data() << "\n";
#endif
return m;
#endif /* End of LLVM <= 3.5 Old JIT section ^^^^^^^^^^^^^^^^^^^^^ */
#if OSL_LLVM_VERSION >= 36 /* MCJIT vvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
# if OSL_LLVM_VERSION >= 40
typedef llvm::Expected<std::unique_ptr<llvm::Module> > ErrorOrModule;
# else
typedef llvm::ErrorOr<std::unique_ptr<llvm::Module> > ErrorOrModule;
# endif
# if OSL_LLVM_VERSION >= 40 || defined(OSL_FORCE_BITCODE_PARSE)
llvm::MemoryBufferRef buf =
llvm::MemoryBufferRef(llvm::StringRef(bitcode, size), name);
# ifdef OSL_FORCE_BITCODE_PARSE
@@ -514,18 +398,8 @@ LLVM_Util::module_from_bitcode (const char *bitcode, size_t size,
ErrorOrModule ModuleOrErr = llvm::getLazyBitcodeModule(buf, context());
# endif
# else /* !OSL_FORCE_BITCODE_PARSE */
std::unique_ptr<llvm::MemoryBuffer> buf (
llvm::MemoryBuffer::getMemBuffer (llvm::StringRef(bitcode, size), name, false));
ErrorOrModule ModuleOrErr = llvm::getLazyBitcodeModule(std::move(buf), context());
# endif
if (err) {
# if OSL_LLVM_VERSION >= 40
error_string(ModuleOrErr.takeError(), err);
# else
error_string(ModuleOrErr.getError(), err);
# endif
}
llvm::Module *m = ModuleOrErr ? ModuleOrErr->release() : nullptr;
# if 0
@@ -534,8 +408,6 @@ LLVM_Util::module_from_bitcode (const char *bitcode, size_t size,
std::cout << " found " << i->getName().data() << "\n";
# endif
return m;
#endif /* MCJIT ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
}
@@ -574,24 +446,14 @@ LLVM_Util::make_jit_execengine (std::string *err)
execengine (NULL); // delete and clear any existing engine
if (err)
err->clear ();
# if OSL_LLVM_VERSION >= 36
llvm::EngineBuilder engine_builder ((std::unique_ptr<llvm::Module>(module())));
# else /* < 36: */
llvm::EngineBuilder engine_builder (module());
# endif
engine_builder.setEngineKind (llvm::EngineKind::JIT);
engine_builder.setErrorStr (err);
#if USE_OLD_JIT
engine_builder.setJITMemoryManager (m_llvm_jitmm);
// N.B. createJIT will take ownership of the the JITMemoryManager!
engine_builder.setUseMCJIT (0);
#else
// We are actually holding a LLVMMemoryManager
engine_builder.setMCJITMemoryManager (std::unique_ptr<llvm::RTDyldMemoryManager>
(new MemoryManager(reinterpret_cast<LLVMMemoryManager*>(m_llvm_jitmm))));
#endif /* USE_OLD_JIT */
(new MemoryManager(m_llvm_jitmm)));
engine_builder.setOptLevel (llvm::CodeGenOpt::Default);
@@ -599,6 +461,17 @@ LLVM_Util::make_jit_execengine (std::string *err)
if (! m_llvm_exec)
return NULL;
// These magic lines will make it so that enough symbol information
// is injected so that running vtune will kinda tell you which shaders
// you're in, and sometimes which function (only for functions that don't
// get inlined. There doesn't seem to be any perf hit from this, either
// in code quality or JIT time. It is only enabled, however, if your copy
// of LLVM was build with -DLLVM_USE_INTEL_JITEVENTS=ON, otherwise
// createIntelJITEventListener() is a stub that just returns nullptr.
auto vtuneProfiler = llvm::JITEventListener::createIntelJITEventListener();
if (vtuneProfiler)
m_llvm_exec->RegisterJITEventListener (vtuneProfiler);
// Force it to JIT as soon as we ask it for the code pointer,
// don't take any chances that it might JIT lazily, since we
// will be stealing the JIT code memory from under its nose and
@@ -623,8 +496,7 @@ LLVM_Util::getPointerToFunction (llvm::Function *func)
{
DASSERT (func && "passed NULL to getPointerToFunction");
llvm::ExecutionEngine *exec = execengine();
if (USE_MCJIT)
exec->finalizeObject ();
exec->finalizeObject ();
void *f = exec->getPointerToFunction (func);
ASSERT (f && "could not getPointerToFunction");
return f;
@@ -648,10 +520,6 @@ LLVM_Util::setup_optimization_passes (int optlevel)
// Construct the per-function passes and module-wide (interprocedural
// optimization) passes.
//
// LLVM keeps changing names and call sequence. This part is easier to
// understand if we explicitly break it into individual LLVM versions.
#if OSL_LLVM_VERSION >= 37
m_llvm_func_passes = new llvm::legacy::FunctionPassManager(module());
llvm::legacy::FunctionPassManager &fpm = (*m_llvm_func_passes);
@@ -659,28 +527,6 @@ LLVM_Util::setup_optimization_passes (int optlevel)
m_llvm_module_passes = new llvm::legacy::PassManager;
llvm::legacy::PassManager &mpm = (*m_llvm_module_passes);
#elif OSL_LLVM_VERSION >= 36
m_llvm_func_passes = new llvm::legacy::FunctionPassManager(module());
llvm::legacy::FunctionPassManager &fpm (*m_llvm_func_passes);
fpm.add (new llvm::DataLayoutPass());
m_llvm_module_passes = new llvm::legacy::PassManager;
llvm::legacy::PassManager &mpm (*m_llvm_module_passes);
mpm.add (new llvm::DataLayoutPass());
#elif OSL_LLVM_VERSION == 35
m_llvm_func_passes = new llvm::legacy::FunctionPassManager(module());
llvm::legacy::FunctionPassManager &fpm (*m_llvm_func_passes);
fpm.add (new llvm::DataLayoutPass(module()));
m_llvm_module_passes = new llvm::legacy::PassManager;
llvm::legacy::PassManager &mpm (*m_llvm_module_passes);
mpm.add (new llvm::DataLayoutPass(module()));
#endif
if (optlevel >= 1 && optlevel <= 3) {
// For LLVM 3.0 and higher, llvm_optimize 1-3 means to use the
// same set of optimizations as clang -O1, -O2, -O3
@@ -700,10 +546,7 @@ LLVM_Util::setup_optimization_passes (int optlevel)
mpm.add (llvm::createCFGSimplificationPass());
// Change memory references to registers
// mpm.add (llvm::createPromoteMemoryToRegisterPass());
#if OSL_LLVM_VERSION <= 36
// Is there a replacement for this in newer LLVM?
mpm.add (llvm::createScalarReplAggregatesPass());
#endif
// Combine instructions where possible -- peephole opts & bit-twiddling
mpm.add (llvm::createInstructionCombiningPass());
// Inline small functions
@@ -734,7 +577,7 @@ LLVM_Util::do_optimize (std::string *out_err)
{
ASSERT(m_llvm_module && "No module to optimize!");
#if OSL_LLVM_VERSION > 35 && !defined(OSL_FORCE_BITCODE_PARSE)
#if !defined(OSL_FORCE_BITCODE_PARSE)
LLVMErr err = m_llvm_module->materializeAll();
if (error_string(std::move(err), out_err))
return;
@@ -752,13 +595,8 @@ LLVM_Util::internalize_module_functions (const std::string &prefix,
const std::vector<std::string> &exceptions,
const std::vector<std::string> &moreexceptions)
{
#if OSL_LLVM_VERSION < 40
for (llvm::Module::iterator iter = module()->begin(); iter != module()->end(); iter++) {
llvm::Function *sym = static_cast<llvm::Function*>(iter);
#else
for (llvm::Function& func : module()->getFunctionList()) {
llvm::Function *sym = &func;
#endif
std::string symname = sym->getName();
if (prefix.size() && ! OIIO::Strutil::starts_with(symname, prefix))
continue;
@@ -874,11 +712,7 @@ LLVM_Util::current_function_arg (int a)
llvm::Function::arg_iterator arg_it = current_function()->arg_begin();
for (int i = 0; i < a; ++i)
++arg_it;
#if OSL_LLVM_VERSION <= 36
return arg_it;
#else
return &(*arg_it);
#endif
}
@@ -1162,6 +996,14 @@ LLVM_Util::ptr_cast (llvm::Value* val, const TypeDesc &type)
llvm::Value *
LLVM_Util::int_to_ptr_cast (llvm::Value* val)
{
return builder().CreateIntToPtr(val,type_void_ptr());
}
llvm::Value *
LLVM_Util::void_ptr (llvm::Value* val)
{
@@ -1313,7 +1155,8 @@ LLVM_Util::op_return (llvm::Value *retval)
void
LLVM_Util::op_memset (llvm::Value *ptr, int val, int len, int align)
{
op_memset(ptr, val, constant(len), align);
builder().CreateMemSet (ptr, builder().getInt8((unsigned char)val),
uint64_t(len), (unsigned)align);
}
@@ -1321,35 +1164,8 @@ LLVM_Util::op_memset (llvm::Value *ptr, int val, int len, int align)
void
LLVM_Util::op_memset (llvm::Value *ptr, int val, llvm::Value *len, int align)
{
// memset with i32 len
// and with an i8 pointer (dst) for LLVM-2.8
llvm::Type* types[] = {
(llvm::Type *) llvm::PointerType::get(llvm::Type::getInt8Ty(context()), 0),
(llvm::Type *) llvm::Type::getInt32Ty(context())
};
llvm::Function* func = llvm::Intrinsic::getDeclaration (module(),
llvm::Intrinsic::memset,
llvm::ArrayRef<llvm::Type *>(types, sizeof(types)/sizeof(llvm::Type*)));
// NOTE(boulos): constant(0) would return an i32
// version of 0, but we need the i8 version. If we make an
// ::constant(char val) though then we'll get ambiguity
// everywhere.
llvm::Value* fill_val = llvm::ConstantInt::get (context(),
llvm::APInt(8, val));
// Non-volatile (allow optimizer to move it around as it wishes
// and even remove it if it can prove it's useless)
#if OSL_LLVM_VERSION <= 36
builder().CreateCall5 (func, ptr, fill_val, len, constant(align),
constant_bool(false));
#else
llvm::Value *args[5] = {
ptr, fill_val, len, constant(align), constant_bool(false)
};
builder().CreateCall (func, llvm::ArrayRef<llvm::Value*>(args, 5));
#endif
builder().CreateMemSet (ptr, builder().getInt8((unsigned char)val),
len, (unsigned)align);
}
@@ -1357,28 +1173,21 @@ LLVM_Util::op_memset (llvm::Value *ptr, int val, llvm::Value *len, int align)
void
LLVM_Util::op_memcpy (llvm::Value *dst, llvm::Value *src, int len, int align)
{
// i32 len
// and with i8 pointers (dst and src) for LLVM-2.8
llvm::Type* types[] = {
(llvm::Type *) llvm::PointerType::get(llvm::Type::getInt8Ty(context()), 0),
(llvm::Type *) llvm::PointerType::get(llvm::Type::getInt8Ty(context()), 0),
(llvm::Type *) llvm::Type::getInt32Ty(context())
};
op_memcpy (dst, align, src, align, len);
}
llvm::Function* func = llvm::Intrinsic::getDeclaration (module(),
llvm::Intrinsic::memcpy,
llvm::ArrayRef<llvm::Type *>(types, sizeof(types)/sizeof(llvm::Type*)));
// Non-volatile (allow optimizer to move it around as it wishes
// and even remove it if it can prove it's useless)
#if OSL_LLVM_VERSION <= 36
builder().CreateCall5 (func, dst, src,
constant(len), constant(align), constant_bool(false));
void
LLVM_Util::op_memcpy (llvm::Value *dst, int dstalign,
llvm::Value *src, int srcalign, int len)
{
#if OSL_LLVM_VERSION >= 70
builder().CreateMemCpy (dst, (unsigned)dstalign, src, (unsigned)srcalign,
uint64_t(len));
#else
llvm::Value *args[5] = {
dst, src, constant(len), constant(align), constant_bool(false)
};
builder().CreateCall (func, llvm::ArrayRef<llvm::Value*>(args, 5));
builder().CreateMemCpy (dst, src, uint64_t(len),
std::min ((unsigned)dstalign, (unsigned)srcalign));
#endif
}
@@ -1419,11 +1228,7 @@ LLVM_Util::GEP (llvm::Value *ptr, int elem)
llvm::Value *
LLVM_Util::GEP (llvm::Value *ptr, int elem1, int elem2)
{
#if OSL_LLVM_VERSION <= 36
return builder().CreateConstGEP2_32 (ptr, elem1, elem2);
#else
return builder().CreateConstGEP2_32 (nullptr, ptr, elem1, elem2);
#endif
}
@@ -1521,6 +1326,14 @@ LLVM_Util::op_float_to_double (llvm::Value* a)
llvm::Value *
LLVM_Util::op_int_to_longlong (llvm::Value* a)
{
ASSERT (a->getType() == type_int());
return builder().CreateSExt(a, llvm::Type::getInt64Ty(context()));
}
llvm::Value *
LLVM_Util::op_int_to_float (llvm::Value* a)
{
@@ -1674,19 +1487,126 @@ LLVM_Util::op_le (llvm::Value *a, llvm::Value *b, bool ordered)
void
LLVM_Util::write_bitcode_file (const char *filename, std::string *err)
{
#if OSL_LLVM_VERSION >= 36
std::error_code local_error;
llvm::raw_fd_ostream out (filename, local_error, llvm::sys::fs::F_None);
if (! out.has_error()) {
#if OSL_LLVM_VERSION >= 70
llvm::WriteBitcodeToFile (*module(), out);
#else
std::string local_error;
llvm::raw_fd_ostream out (filename, err ? *err : local_error, llvm::sys::fs::F_None);
llvm::WriteBitcodeToFile (module(), out);
#endif
llvm::WriteBitcodeToFile (module(), out);
if (err && local_error)
*err = local_error.message ();
}
}
#if OSL_LLVM_VERSION >= 36
if (err && local_error)
*err = local_error.message ();
bool
LLVM_Util::ptx_compile_group (llvm::Module* lib_module, const std::string& name,
std::string& out)
{
std::string target_triple = module()->getTargetTriple();
ASSERT (lib_module->getTargetTriple() == target_triple &&
"PTX compile error: Shader and renderer bitcode library targets do not match");
// Create a new empty module to hold the linked shadeops and compiled
// ShaderGroup
llvm::Module* linked_module = new_module (name.c_str());
// First, link in the cloned ShaderGroup module
#if OSL_LLVM_VERSION >= 70
std::unique_ptr<llvm::Module> mod_ptr = llvm::CloneModule (*module());
#else
std::unique_ptr<llvm::Module> mod_ptr = llvm::CloneModule (module());
#endif
bool failed = llvm::Linker::linkModules (*linked_module, std::move (mod_ptr));
if (failed) {
ASSERT (0 && "PTX compile error: Unable to link group module");
}
// Second, link in the shadeops library, keeping only the functions that are needed
std::unique_ptr<llvm::Module> lib_ptr (lib_module);
failed = llvm::Linker::linkModules (*linked_module, std::move (lib_ptr));
// Internalize the Globals to match code generated by NVCC
for (auto& g_var : linked_module->globals()) {
g_var.setLinkage(llvm::GlobalValue::InternalLinkage);
}
// Verify that the NVPTX target has been initialized
std::string error;
const llvm::Target* llvm_target =
llvm::TargetRegistry::lookupTarget (target_triple, error);
if(! llvm_target) {
ASSERT (0 && "PTX compile error: LLVM Target is not initialized");
}
llvm::TargetOptions options;
options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
options.UnsafeFPMath = 1;
options.NoInfsFPMath = 1;
options.NoNaNsFPMath = 1;
options.HonorSignDependentRoundingFPMathOption = 0;
options.FloatABIType = llvm::FloatABI::Default;
options.AllowFPOpFusion = llvm::FPOpFusion::Fast;
options.NoZerosInBSS = 0;
options.GuaranteedTailCallOpt = 0;
options.StackAlignmentOverride = 0;
options.UseInitArray = 0;
llvm::TargetMachine* target_machine = llvm_target->createTargetMachine(
target_triple, "sm_35", "+ptx50", options,
llvm::Reloc::Static, llvm::CodeModel::Small, llvm::CodeGenOpt::Aggressive);
if (! target_machine) {
ASSERT(0 && "PTX compile error: Unable to create target machine -- is NVPTX enabled in LLVM?");
}
// Setup the optimzation passes
llvm::legacy::FunctionPassManager fn_pm (linked_module);
fn_pm.add (llvm::createTargetTransformInfoWrapperPass (
target_machine->getTargetIRAnalysis()));
llvm::legacy::PassManager mod_pm;
mod_pm.add (new llvm::TargetLibraryInfoWrapperPass (llvm::Triple (target_triple)));
mod_pm.add (llvm::createTargetTransformInfoWrapperPass (
target_machine->getTargetIRAnalysis()));
mod_pm.add (llvm::createRewriteSymbolsPass());
// Make sure the 'flush-to-zero' instruction variants are used when possible
linked_module->addModuleFlag (llvm::Module::Override, "nvvm-reflect-ftz", 1);
for (llvm::Function& fn : *linked_module) {
fn.addFnAttr ("nvptx-f32ftz", "true");
}
llvm::SmallString<4096> assembly;
llvm::raw_svector_ostream assembly_stream (assembly);
// TODO: Make sure rounding modes, etc., are set correctly
#if OSL_LLVM_VERSION >= 70
target_machine->addPassesToEmitFile (mod_pm, assembly_stream,
nullptr, // FIXME: Correct?
llvm::TargetMachine::CGFT_AssemblyFile);
#else
target_machine->addPassesToEmitFile (mod_pm, assembly_stream,
llvm::TargetMachine::CGFT_AssemblyFile);
#endif
// Run the optimization passes on the functions
fn_pm.doInitialization();
for (llvm::Module::iterator i = linked_module->begin(); i != linked_module->end(); i++) {
fn_pm.run (*i);
}
// Run the optimization passes on the module to generate the PTX
mod_pm.run (*linked_module);
// TODO: Minimize string copying
out = assembly_stream.str().str();
delete linked_module;
return true;
}
@@ -1702,6 +1622,20 @@ LLVM_Util::bitcode_string (llvm::Function *func)
std::string
LLVM_Util::bitcode_string (llvm::Module *module)
{
std::string s;
llvm::raw_string_ostream stream (s);
for (auto&& func : module->getFunctionList())
stream << func << '\n';
return stream.str();
}
void
LLVM_Util::delete_func_body (llvm::Function *func)
{
+71 -89
View File
@@ -331,129 +331,109 @@ OSOReaderToMaster::parameter_done ()
inline bool
starts_with (const std::string &source, const std::string &pattern)
{
return ! strncmp (source.c_str(), pattern.c_str(), pattern.length());
}
// If the string 'source' begins with 'pattern', erase the pattern from
// the start of source and return true. Otherwise, do not alter source
// and return false.
inline bool
extract_prefix (std::string &source, const std::string &pattern)
{
if (starts_with (source, pattern)) {
source.erase (0, pattern.length());
return true;
}
return false;
}
// Return the prefix of source that doesn't contain any characters in
// 'stop', erase that prefix from source (up to and including the stop
// character. Also, the returned string is trimmed of leading and trailing
// spaces if 'do_trim' is true.
static std::string
readuntil (std::string &source, const std::string &stop, bool do_trim=false)
{
size_t e = source.find_first_of (stop);
if (e == source.npos)
return std::string ();
std::string r (source, 0, e);
source.erase (0, e == source.npos ? e : e+1);
if (do_trim)
r = Strutil::strip (r); // trim whitespace
return r;
}
void
OSOReaderToMaster::hint (string_view hintstring)
{
std::string h (hintstring); // FIXME -- use string_view ops here
if (extract_prefix (h, "%filename{\"")) {
m_sourcefile = readuntil (h, "\"");
string_view h (hintstring);
if (Strutil::parse_prefix (h, "%filename{\"")) {
m_sourcefile = Strutil::parse_until (h, "\"");
return;
}
if (extract_prefix (h, "%line{")) {
m_sourceline = atoi (h.c_str());
if (Strutil::parse_prefix (h, "%line{")) {
Strutil::parse_int (h, m_sourceline);
return;
}
if (extract_prefix (h, "%structfields{")) {
ASSERT (m_master->m_symbols.size() && "structfields hint but no sym");
if (Strutil::parse_prefix (h, "%structfields{") && m_master->m_symbols.size()) {
Symbol &sym (m_master->m_symbols.back());
StructSpec *structspec = sym.typespec().structspec();
if (structspec->numfields() == 0) {
while (1) {
std::string afield = readuntil (h, ",}", true);
std::string afield = Strutil::parse_until (h, ",}");
Strutil::parse_char (h, ','); // skip the separator
if (! afield.length())
break;
// std::cerr << " struct field " << afield << "\n";
structspec->add_field (TypeSpec(), ustring(afield));
}
}
return;
}
if (extract_prefix (h, "%mystructfield{")) {
ASSERT (m_master->m_symbols.size() && "mystructfield hint but no sym");
Symbol &sym (m_master->m_symbols.back());
sym.fieldid (atoi(h.c_str()+15));
if (Strutil::parse_prefix (h, "%mystructfield{") && m_master->m_symbols.size()) {
int ival = -1;
if (Strutil::parse_int (h, ival) && ival >= 0)
m_master->m_symbols.back().fieldid (ival);
return;
}
if (extract_prefix (h, "%read{")) {
ASSERT (m_master->m_symbols.size() && "read hint but no sym");
if (Strutil::parse_prefix (h, "%read{") && m_master->m_symbols.size()) {
Symbol &sym (m_master->m_symbols.back());
int first, last;
sscanf (h.c_str(), "%d,%d", &first, &last);
sym.set_read (first, last);
if (Strutil::parse_int (h, first) && Strutil::parse_char(h, ',')
&& Strutil::parse_int (h, last))
sym.set_read (first, last);
return;
}
if (extract_prefix (h, "%write{")) {
ASSERT (m_master->m_symbols.size() && "write hint but no sym");
if (Strutil::parse_prefix (h, "%write{") && m_master->m_symbols.size()) {
Symbol &sym (m_master->m_symbols.back());
int first, last;
sscanf (h.c_str(), "%d,%d", &first, &last);
sym.set_write (first, last);
if (Strutil::parse_int (h, first) && Strutil::parse_char(h, ',')
&& Strutil::parse_int (h, last))
sym.set_write (first, last);
return;
}
if (extract_prefix(h, "%argrw{")) {
const char* str = h.c_str();
ASSERT(*str == '\"');
str++; // skip open quote
size_t i = 0;
for (; *str != '\"'; i++, str++) {
ASSERT(*str == 'r' || *str == 'w' || *str == 'W' || *str == '-');
m_master->m_ops.back().argwrite(i, *str == 'w' || *str =='W');
m_master->m_ops.back().argread(i, *str == 'r' || *str =='W');
if (Strutil::parse_prefix(h, "%argrw{") && m_master->m_ops.size()) {
Opcode &op (m_master->m_ops.back());
string_view str = Strutil::parse_until (h, "}");
Strutil::parse_string (str, str, false, Strutil::DeleteQuotes);
if (str.size() != m_nargs) {
m_shadingsys.error ("Parsing shader %s: malformed hint '%s' on op %s line %d",
m_master->shadername(), hintstring,
m_master->m_ops.back().opname(), m_sourceline);
m_errors = true;
}
for (size_t i = 0; str.size() && i < m_nargs; i++, str.remove_prefix(1)) {
char c = str.front();
op.argwrite (i, c == 'w' || c =='W');
op.argread (i, c == 'r' || c =='W');
}
ASSERT(m_nargs == i);
// Fix old bug where oslc forgot to mark getmatrix last arg as write
ustring opname = m_master->m_ops.back().opname();
static ustring getmatrix("getmatrix");
if (m_master->m_ops.back().opname() == getmatrix)
m_master->m_ops.back().argwrite(m_nargs-1, true);
if (opname == getmatrix)
m_master->m_ops.back().argwriteonly (m_nargs-1);
// Fix old bug where oslc forgot to mark regex results as write.
// This was a bug prior to 1.10.
static ustring regex_search("regex_search");
static ustring regex_match("regex_match");
if (opname == regex_search || opname == regex_search)
m_master->m_ops.back().argwriteonly (2);
return;
}
if (extract_prefix(h, "%argderivs{")) {
if (Strutil::parse_prefix(h, "%argderivs{")) {
while (1) {
std::string afield = readuntil (h, ",}", true);
string_view afield = Strutil::parse_until (h, ",}");
Strutil::parse_char (h, ','); // skip the separator
if (! afield.length())
break;
int arg = atoi (afield.c_str());
if (arg >= 0)
int arg = -1;
if (Strutil::parse_int (afield, arg) && arg >= 0)
m_master->m_ops.back().argtakesderivs (arg, true);
}
return;
}
if (extract_prefix (h, "%meta{") && m_master->m_symbols.size()) {
if (Strutil::parse_prefix (h, "%meta{") && m_master->m_symbols.size()) {
Symbol &sym (m_master->m_symbols.back());
int lockval = -1;
int ok = sscanf (h.c_str(), " int , lockgeom , %d", &lockval);
if (ok)
sym.lockgeom (lockval);
int ival = -1;
TypeDesc type (Strutil::parse_identifier (h, "", true));
Strutil::parse_char (h, ',');
string_view ident = Strutil::parse_identifier (h, "", true);
Strutil::parse_char (h, ',');
if (type == TypeDesc::TypeInt && ident == "lockgeom"
&& Strutil::parse_int (h, ival) && ival >= 0)
sym.lockgeom (ival);
else if (type == TypeDesc::TypeInt && ident == "allowconnect"
&& Strutil::parse_int (h, ival) && ival >= 0)
sym.allowconnect (ival);
return;
}
}
@@ -497,7 +477,7 @@ OSOReaderToMaster::codeend ()
// If we were previously chalking up the code to init ops for a
// symbol, mark the end.
m_master->symbol(m_codesym)->initend (nextop);
} else if (m_codesection && m_codesection == "___main___") {
} else if (m_codesection == "___main___") {
// If we were previously reading ops for the ___main___ entry
// point, mark its end properly.
m_master->m_maincodeend = nextop;
@@ -585,10 +565,12 @@ ShadingSystemImpl::loadshader (string_view cname)
// Not found in the map
OSOReaderToMaster oso (*this);
bool testcwd = m_searchpath_dirs.empty(); // test "." if there's no searchpath
std::string filename = OIIO::Filesystem::searchpath_find (name.string() + ".oso",
m_searchpath_dirs);
m_searchpath_dirs,
testcwd);
if (filename.empty ()) {
error ("No .oso file could be found for shader \"%s\"", name.c_str());
error ("No .oso file could be found for shader \"%s\"", name);
return NULL;
}
OIIO::Timer timer;
@@ -636,9 +618,9 @@ ShadingSystemImpl::LoadMemoryCompiledShader (string_view shadername,
ustring name (shadername);
lock_guard guard (m_mutex); // Thread safety
ShaderNameMap::const_iterator found = m_shader_masters.find (name);
if (found != m_shader_masters.end()) {
if (found != m_shader_masters.end() && ! allow_shader_replacement()) {
if (debug())
info ("Preload shader %s already exists in shader_masters", name.c_str());
info ("Preload shader %s already exists in shader_masters", name);
return false;
}
+5 -1
View File
@@ -106,7 +106,7 @@ Parser::buildStop(LPexp *etype, LPexp *scatter, const std::list<LPexp*> &custom)
LPexp *
Parser::parseSymbol()
{
bool iscustom;
bool iscustom = false;
ustring sym = parseRawSymbol(iscustom);
if (m_ingroup) {
if (sym == udot)
@@ -396,6 +396,10 @@ LPexp *
Parser::parseModifier(LPexp *e)
{
if (hasInput()) {
if (m_ingroup && (head() == '*' || head() == '{' || head() == '+')) {
m_error = std::string("Repetitions not allowed inside '<...>'");
return NULL;
}
if (head() == '*') {
next();
return new lpexp::Repeat(e);
+1 -1
View File
@@ -264,7 +264,7 @@ ShaderMaster::print ()
for (size_t j = 0; j < Opcode::max_jumps; ++j)
if (m_ops[i].jump(j) >= 0)
out << " " << m_ops[i].jump(j);
if (m_ops[i].sourcefile())
if (!m_ops[i].sourcefile().empty())
out << "\t(" << m_ops[i].sourcefile() << ":"
<< m_ops[i].sourceline() << ")";
out << "\n";
+5 -1
View File
@@ -539,6 +539,8 @@ ShadingContext::ocio_transform (ustring fromspace, ustring tospace,
tospace != m_last_colorproc_tospace) {
OIIO::ColorConfig& cc (shadingsys().m_colorconfig);
m_last_colorproc = cc.createColorProcessor (fromspace, tospace);
m_last_colorproc_fromspace = fromspace;
m_last_colorproc_tospace = tospace;
}
if (m_last_colorproc)
m_last_colorproc->apply ((float *)&Cout);
@@ -563,13 +565,15 @@ ShadingContext::ocio_transform (ustring fromspace, ustring tospace,
tospace != m_last_colorproc_tospace) {
OIIO::ColorConfig& cc (shadingsys().m_colorconfig);
m_last_colorproc = cc.createColorProcessor (fromspace, tospace);
m_last_colorproc_fromspace = fromspace;
m_last_colorproc_tospace = tospace;
}
if (m_last_colorproc) {
// Use finite differencing to approximate the derivative. Make 3
// color values to convert.
const float eps = 0.001f;
Color3 CC[3] = { C.val(), C.val() + eps*C.dx(), C.val() + eps*C.dy() };
m_last_colorproc->apply ((float *)&CC, 3, 1, 3, sizeof(Color3), 0, 0);
m_last_colorproc->apply ((float *)&CC, 3, 1, 3, sizeof(float), sizeof(Color3), 0);
Cout.set (CC[0],
(CC[1] - CC[0]) * (1.0f / eps),
(CC[2] - CC[0]) * (1.0f / eps));
+101 -96
View File
@@ -94,28 +94,28 @@ void test_perlin(int d) {
#define NOISE_IMPL(opname,implname) \
OSL_SHADEOP float osl_ ##opname## _ff (float x) { \
OSL_SHADEOP OSL_HOSTDEVICE float osl_ ##opname## _ff (float x) { \
implname impl; \
float r; \
impl (r, x); \
return r; \
} \
\
OSL_SHADEOP float osl_ ##opname## _fff (float x, float y) { \
OSL_SHADEOP OSL_HOSTDEVICE float osl_ ##opname## _fff (float x, float y) { \
implname impl; \
float r; \
impl (r, x, y); \
return r; \
} \
\
OSL_SHADEOP float osl_ ##opname## _fv (char *x) { \
OSL_SHADEOP OSL_HOSTDEVICE float osl_ ##opname## _fv (char *x) { \
implname impl; \
float r; \
impl (r, VEC(x)); \
return r; \
} \
\
OSL_SHADEOP float osl_ ##opname## _fvf (char *x, float y) { \
OSL_SHADEOP OSL_HOSTDEVICE float osl_ ##opname## _fvf (char *x, float y) { \
implname impl; \
float r; \
impl (r, VEC(x), y); \
@@ -123,22 +123,22 @@ OSL_SHADEOP float osl_ ##opname## _fvf (char *x, float y) { \
} \
\
\
OSL_SHADEOP void osl_ ##opname## _vf (char *r, float x) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _vf (char *r, float x) { \
implname impl; \
impl (VEC(r), x); \
} \
\
OSL_SHADEOP void osl_ ##opname## _vff (char *r, float x, float y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _vff (char *r, float x, float y) { \
implname impl; \
impl (VEC(r), x, y); \
} \
\
OSL_SHADEOP void osl_ ##opname## _vv (char *r, char *x) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _vv (char *r, char *x) { \
implname impl; \
impl (VEC(r), VEC(x)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _vvf (char *r, char *x, float y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _vvf (char *r, char *x, float y) { \
implname impl; \
impl (VEC(r), VEC(x), y); \
}
@@ -148,83 +148,83 @@ OSL_SHADEOP void osl_ ##opname## _vvf (char *r, char *x, float y) { \
#define NOISE_IMPL_DERIV(opname,implname) \
OSL_SHADEOP void osl_ ##opname## _dfdf (char *r, char *x) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dfdf (char *r, char *x) { \
implname impl; \
impl (DFLOAT(r), DFLOAT(x)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dfdfdf (char *r, char *x, char *y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dfdfdf (char *r, char *x, char *y) { \
implname impl; \
impl (DFLOAT(r), DFLOAT(x), DFLOAT(y)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dfdff (char *r, char *x, float y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dfdff (char *r, char *x, float y) { \
implname impl; \
impl (DFLOAT(r), DFLOAT(x), Dual2<float>(y)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dffdf (char *r, float x, char *y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dffdf (char *r, float x, char *y) { \
implname impl; \
impl (DFLOAT(r), Dual2<float>(x), DFLOAT(y)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dfdv (char *r, char *x) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dfdv (char *r, char *x) { \
implname impl; \
impl (DFLOAT(r), DVEC(x)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dfdvdf (char *r, char *x, char *y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dfdvdf (char *r, char *x, char *y) { \
implname impl; \
impl (DFLOAT(r), DVEC(x), DFLOAT(y)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dfdvf (char *r, char *x, float y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dfdvf (char *r, char *x, float y) { \
implname impl; \
impl (DFLOAT(r), DVEC(x), Dual2<float>(y)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dfvdf (char *r, char *x, char *y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dfvdf (char *r, char *x, char *y) { \
implname impl; \
impl (DFLOAT(r), Dual2<Vec3>(VEC(x)), DFLOAT(y)); \
} \
\
\
OSL_SHADEOP void osl_ ##opname## _dvdf (char *r, char *x) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dvdf (char *r, char *x) { \
implname impl; \
impl (DVEC(r), DFLOAT(x)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dvdfdf (char *r, char *x, char *y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dvdfdf (char *r, char *x, char *y) { \
implname impl; \
impl (DVEC(r), DFLOAT(x), DFLOAT(y)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dvdff (char *r, char *x, float y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dvdff (char *r, char *x, float y) { \
implname impl; \
impl (DVEC(r), DFLOAT(x), Dual2<float>(y)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dvfdf (char *r, float x, char *y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dvfdf (char *r, float x, char *y) { \
implname impl; \
impl (DVEC(r), Dual2<float>(x), DFLOAT(y)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dvdv (char *r, char *x) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dvdv (char *r, char *x) { \
implname impl; \
impl (DVEC(r), DVEC(x)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dvdvdf (char *r, char *x, char *y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dvdvdf (char *r, char *x, char *y) { \
implname impl; \
impl (DVEC(r), DVEC(x), DFLOAT(y)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dvdvf (char *r, char *x, float y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dvdvf (char *r, char *x, float y) { \
implname impl; \
impl (DVEC(r), DVEC(x), Dual2<float>(y)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dvvdf (char *r, char *x, char *y) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _dvvdf (char *r, char *x, char *y) { \
implname impl; \
impl (DVEC(r), Dual2<Vec3>(VEC(x)), DFLOAT(y)); \
}
@@ -235,43 +235,43 @@ OSL_SHADEOP void osl_ ##opname## _dvvdf (char *r, char *x, char *y) { \
#define NOISE_IMPL_DERIV_OPT(opname,implname) \
OSL_SHADEOP void osl_ ##opname## _dfdf (char *name, char *r, char *x, char *sg, char *opt) { \
implname impl; \
impl (USTR(name), DFLOAT(r), DFLOAT(x), (ShaderGlobals *)sg, (NoiseParams *)opt); \
impl (USTR(name), DFLOAT(r), DFLOAT(x), (ShaderGlobals *)sg, (NoiseParams *)opt); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dfdfdf (char *name, char *r, char *x, char *y, char *sg, char *opt) { \
implname impl; \
impl (USTR(name), DFLOAT(r), DFLOAT(x), DFLOAT(y), (ShaderGlobals *)sg, (NoiseParams *)opt); \
impl (USTR(name), DFLOAT(r), DFLOAT(x), DFLOAT(y), (ShaderGlobals *)sg, (NoiseParams *)opt); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dfdv (char *name, char *r, char *x, char *sg, char *opt) { \
OSL_SHADEOP void osl_ ##opname## _dfdv (char *name, char *r, char *x, char *sg, char *opt) { \
implname impl; \
impl (USTR(name), DFLOAT(r), DVEC(x), (ShaderGlobals *)sg, (NoiseParams *)opt); \
impl (USTR(name), DFLOAT(r), DVEC(x), (ShaderGlobals *)sg, (NoiseParams *)opt); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dfdvdf (char *name, char *r, char *x, char *y, char *sg, char *opt) { \
implname impl; \
impl (USTR(name), DFLOAT(r), DVEC(x), DFLOAT(y), (ShaderGlobals *)sg, (NoiseParams *)opt); \
impl (USTR(name), DFLOAT(r), DVEC(x), DFLOAT(y), (ShaderGlobals *)sg, (NoiseParams *)opt); \
} \
\
\
OSL_SHADEOP void osl_ ##opname## _dvdf (char *name, char *r, char *x, char *sg, char *opt) { \
OSL_SHADEOP void osl_ ##opname## _dvdf (char *name, char *r, char *x, char *sg, char *opt) { \
implname impl; \
impl (USTR(name), DVEC(r), DFLOAT(x), (ShaderGlobals *)sg, (NoiseParams *)opt); \
impl (USTR(name), DVEC(r), DFLOAT(x), (ShaderGlobals *)sg, (NoiseParams *)opt); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dvdfdf (char *name, char *r, char *x, char *y, char *sg, char *opt) { \
implname impl; \
impl (USTR(name), DVEC(r), DFLOAT(x), DFLOAT(y), (ShaderGlobals *)sg, (NoiseParams *)opt); \
impl (USTR(name), DVEC(r), DFLOAT(x), DFLOAT(y), (ShaderGlobals *)sg, (NoiseParams *)opt); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dvdv (char *name, char *r, char *x, char *sg, char *opt) { \
OSL_SHADEOP void osl_ ##opname## _dvdv (char *name, char *r, char *x, char *sg, char *opt) { \
implname impl; \
impl (USTR(name), DVEC(r), DVEC(x), (ShaderGlobals *)sg, (NoiseParams *)opt); \
impl (USTR(name), DVEC(r), DVEC(x), (ShaderGlobals *)sg, (NoiseParams *)opt); \
} \
\
OSL_SHADEOP void osl_ ##opname## _dvdvdf (char *name, char *r, char *x, char *y, char *sg, char *opt) { \
implname impl; \
impl (USTR(name), DVEC(r), DVEC(x), DFLOAT(y), (ShaderGlobals *)sg, (NoiseParams *)opt); \
impl (USTR(name), DVEC(r), DVEC(x), DFLOAT(y), (ShaderGlobals *)sg, (NoiseParams *)opt); \
}
@@ -291,28 +291,28 @@ NOISE_IMPL_DERIV (usimplexnoise, USimplexNoise)
#define PNOISE_IMPL(opname,implname) \
OSL_SHADEOP float osl_ ##opname## _fff (float x, float px) { \
OSL_SHADEOP OSL_HOSTDEVICE float osl_ ##opname## _fff (float x, float px) { \
implname impl; \
float r; \
impl (r, x, px); \
return r; \
} \
\
OSL_SHADEOP float osl_ ##opname## _fffff (float x, float y, float px, float py) { \
OSL_SHADEOP OSL_HOSTDEVICE float osl_ ##opname## _fffff (float x, float y, float px, float py) { \
implname impl; \
float r; \
impl (r, x, y, px, py); \
return r; \
} \
\
OSL_SHADEOP float osl_ ##opname## _fvv (char *x, char *px) { \
OSL_SHADEOP OSL_HOSTDEVICE float osl_ ##opname## _fvv (char *x, char *px) { \
implname impl; \
float r; \
impl (r, VEC(x), VEC(px)); \
return r; \
} \
\
OSL_SHADEOP float osl_ ##opname## _fvfvf (char *x, float y, char *px, float py) { \
OSL_SHADEOP OSL_HOSTDEVICE float osl_ ##opname## _fvfvf (char *x, float y, char *px, float py) { \
implname impl; \
float r; \
impl (r, VEC(x), y, VEC(px), py); \
@@ -320,22 +320,22 @@ OSL_SHADEOP float osl_ ##opname## _fvfvf (char *x, float y, char *px, float py)
} \
\
\
OSL_SHADEOP void osl_ ##opname## _vff (char *r, float x, float px) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _vff (char *r, float x, float px) { \
implname impl; \
impl (VEC(r), x, px); \
} \
\
OSL_SHADEOP void osl_ ##opname## _vffff (char *r, float x, float y, float px, float py) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _vffff (char *r, float x, float y, float px, float py) { \
implname impl; \
impl (VEC(r), x, y, px, py); \
} \
\
OSL_SHADEOP void osl_ ##opname## _vvv (char *r, char *x, char *px) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _vvv (char *r, char *x, char *px) { \
implname impl; \
impl (VEC(r), VEC(x), VEC(px)); \
} \
\
OSL_SHADEOP void osl_ ##opname## _vvfvf (char *r, char *x, float y, char *px, float py) { \
OSL_SHADEOP OSL_HOSTDEVICE void osl_ ##opname## _vvfvf (char *r, char *x, float y, char *px, float py) { \
implname impl; \
impl (VEC(r), VEC(x), y, VEC(px), py); \
}
@@ -483,6 +483,11 @@ PNOISE_IMPL_DERIV (psnoise, PeriodicSNoise)
// NB: We are excluding noise functions that require (u)string arguments
// in the CUDA case, since strings are not currently well-supported
// by the PTX backend. We will update this once string support has
// been improved.
struct GaborNoise {
GaborNoise () { }
@@ -609,53 +614,53 @@ PNOISE_IMPL_DERIV_OPT (gaborpnoise, GaborPNoise)
struct NullNoise {
NullNoise () { }
inline void operator() (float &result, float x) const { result = 0.0f; }
inline void operator() (float &result, float x, float y) const { result = 0.0f; }
inline void operator() (float &result, const Vec3 &p) const { result = 0.0f; }
inline void operator() (float &result, const Vec3 &p, float t) const { result = 0.0f; }
inline void operator() (Vec3 &result, float x) const { result = v(); }
inline void operator() (Vec3 &result, float x, float y) const { result = v(); }
inline void operator() (Vec3 &result, const Vec3 &p) const { result = v(); }
inline void operator() (Vec3 &result, const Vec3 &p, float t) const { result = v(); }
inline void operator() (Dual2<float> &result, const Dual2<float> &x,
int seed=0) const { result.set (0.0f, 0.0f, 0.0f); }
inline void operator() (Dual2<float> &result, const Dual2<float> &x,
const Dual2<float> &y, int seed=0) const { result.set (0.0f, 0.0f, 0.0f); }
inline void operator() (Dual2<float> &result, const Dual2<Vec3> &p,
int seed=0) const { result.set (0.0f, 0.0f, 0.0f); }
inline void operator() (Dual2<float> &result, const Dual2<Vec3> &p,
const Dual2<float> &t, int seed=0) const { result.set (0.0f, 0.0f, 0.0f); }
inline void operator() (Dual2<Vec3> &result, const Dual2<float> &x) const { result.set (v(), v(), v()); }
inline void operator() (Dual2<Vec3> &result, const Dual2<float> &x, const Dual2<float> &y) const { result.set (v(), v(), v()); }
inline void operator() (Dual2<Vec3> &result, const Dual2<Vec3> &p) const { result.set (v(), v(), v()); }
inline void operator() (Dual2<Vec3> &result, const Dual2<Vec3> &p, const Dual2<float> &t) const { result.set (v(), v(), v()); }
inline Vec3 v () const { return Vec3(0.0f, 0.0f, 0.0f); };
OSL_HOSTDEVICE NullNoise () { }
OSL_HOSTDEVICE inline void operator() (float &result, float x) const { result = 0.0f; }
OSL_HOSTDEVICE inline void operator() (float &result, float x, float y) const { result = 0.0f; }
OSL_HOSTDEVICE inline void operator() (float &result, const Vec3 &p) const { result = 0.0f; }
OSL_HOSTDEVICE inline void operator() (float &result, const Vec3 &p, float t) const { result = 0.0f; }
OSL_HOSTDEVICE inline void operator() (Vec3 &result, float x) const { result = v(); }
OSL_HOSTDEVICE inline void operator() (Vec3 &result, float x, float y) const { result = v(); }
OSL_HOSTDEVICE inline void operator() (Vec3 &result, const Vec3 &p) const { result = v(); }
OSL_HOSTDEVICE inline void operator() (Vec3 &result, const Vec3 &p, float t) const { result = v(); }
OSL_HOSTDEVICE inline void operator() (Dual2<float> &result, const Dual2<float> &x,
int seed=0) const { result.set (0.0f, 0.0f, 0.0f); }
OSL_HOSTDEVICE inline void operator() (Dual2<float> &result, const Dual2<float> &x,
const Dual2<float> &y, int seed=0) const { result.set (0.0f, 0.0f, 0.0f); }
OSL_HOSTDEVICE inline void operator() (Dual2<float> &result, const Dual2<Vec3> &p,
int seed=0) const { result.set (0.0f, 0.0f, 0.0f); }
OSL_HOSTDEVICE inline void operator() (Dual2<float> &result, const Dual2<Vec3> &p,
const Dual2<float> &t, int seed=0) const { result.set (0.0f, 0.0f, 0.0f); }
OSL_HOSTDEVICE inline void operator() (Dual2<Vec3> &result, const Dual2<float> &x) const { result.set (v(), v(), v()); }
OSL_HOSTDEVICE inline void operator() (Dual2<Vec3> &result, const Dual2<float> &x, const Dual2<float> &y) const { result.set (v(), v(), v()); }
OSL_HOSTDEVICE inline void operator() (Dual2<Vec3> &result, const Dual2<Vec3> &p) const { result.set (v(), v(), v()); }
OSL_HOSTDEVICE inline void operator() (Dual2<Vec3> &result, const Dual2<Vec3> &p, const Dual2<float> &t) const { result.set (v(), v(), v()); }
OSL_HOSTDEVICE inline Vec3 v () const { return Vec3(0.0f, 0.0f, 0.0f); };
};
struct UNullNoise {
UNullNoise () { }
inline void operator() (float &result, float x) const { result = 0.5f; }
inline void operator() (float &result, float x, float y) const { result = 0.5f; }
inline void operator() (float &result, const Vec3 &p) const { result = 0.5f; }
inline void operator() (float &result, const Vec3 &p, float t) const { result = 0.5f; }
inline void operator() (Vec3 &result, float x) const { result = v(); }
inline void operator() (Vec3 &result, float x, float y) const { result = v(); }
inline void operator() (Vec3 &result, const Vec3 &p) const { result = v(); }
inline void operator() (Vec3 &result, const Vec3 &p, float t) const { result = v(); }
inline void operator() (Dual2<float> &result, const Dual2<float> &x,
int seed=0) const { result.set (0.5f, 0.5f, 0.5f); }
inline void operator() (Dual2<float> &result, const Dual2<float> &x,
const Dual2<float> &y, int seed=0) const { result.set (0.5f, 0.5f, 0.5f); }
inline void operator() (Dual2<float> &result, const Dual2<Vec3> &p,
int seed=0) const { result.set (0.5f, 0.5f, 0.5f); }
inline void operator() (Dual2<float> &result, const Dual2<Vec3> &p,
const Dual2<float> &t, int seed=0) const { result.set (0.5f, 0.5f, 0.5f); }
inline void operator() (Dual2<Vec3> &result, const Dual2<float> &x) const { result.set (v(), v(), v()); }
inline void operator() (Dual2<Vec3> &result, const Dual2<float> &x, const Dual2<float> &y) const { result.set (v(), v(), v()); }
inline void operator() (Dual2<Vec3> &result, const Dual2<Vec3> &p) const { result.set (v(), v(), v()); }
inline void operator() (Dual2<Vec3> &result, const Dual2<Vec3> &p, const Dual2<float> &t) const { result.set (v(), v(), v()); }
inline Vec3 v () const { return Vec3(0.5f, 0.5f, 0.5f); };
OSL_HOSTDEVICE UNullNoise () { }
OSL_HOSTDEVICE inline void operator() (float &result, float x) const { result = 0.5f; }
OSL_HOSTDEVICE inline void operator() (float &result, float x, float y) const { result = 0.5f; }
OSL_HOSTDEVICE inline void operator() (float &result, const Vec3 &p) const { result = 0.5f; }
OSL_HOSTDEVICE inline void operator() (float &result, const Vec3 &p, float t) const { result = 0.5f; }
OSL_HOSTDEVICE inline void operator() (Vec3 &result, float x) const { result = v(); }
OSL_HOSTDEVICE inline void operator() (Vec3 &result, float x, float y) const { result = v(); }
OSL_HOSTDEVICE inline void operator() (Vec3 &result, const Vec3 &p) const { result = v(); }
OSL_HOSTDEVICE inline void operator() (Vec3 &result, const Vec3 &p, float t) const { result = v(); }
OSL_HOSTDEVICE inline void operator() (Dual2<float> &result, const Dual2<float> &x,
int seed=0) const { result.set (0.5f, 0.5f, 0.5f); }
OSL_HOSTDEVICE inline void operator() (Dual2<float> &result, const Dual2<float> &x,
const Dual2<float> &y, int seed=0) const { result.set (0.5f, 0.5f, 0.5f); }
OSL_HOSTDEVICE inline void operator() (Dual2<float> &result, const Dual2<Vec3> &p,
int seed=0) const { result.set (0.5f, 0.5f, 0.5f); }
OSL_HOSTDEVICE inline void operator() (Dual2<float> &result, const Dual2<Vec3> &p,
const Dual2<float> &t, int seed=0) const { result.set (0.5f, 0.5f, 0.5f); }
OSL_HOSTDEVICE inline void operator() (Dual2<Vec3> &result, const Dual2<float> &x) const { result.set (v(), v(), v()); }
OSL_HOSTDEVICE inline void operator() (Dual2<Vec3> &result, const Dual2<float> &x, const Dual2<float> &y) const { result.set (v(), v(), v()); }
OSL_HOSTDEVICE inline void operator() (Dual2<Vec3> &result, const Dual2<Vec3> &p) const { result.set (v(), v(), v()); }
OSL_HOSTDEVICE inline void operator() (Dual2<Vec3> &result, const Dual2<Vec3> &p, const Dual2<float> &t) const { result.set (v(), v(), v()); }
OSL_HOSTDEVICE inline Vec3 v () const { return Vec3(0.5f, 0.5f, 0.5f); };
};
NOISE_IMPL (nullnoise, NullNoise)
@@ -876,36 +881,36 @@ osl_count_noise (void *sg_)
OSL_SHADEOP int
OSL_SHADEOP OSL_HOSTDEVICE int
osl_hash_ii (int x)
{
return inthashi (x);
}
OSL_SHADEOP int
OSL_SHADEOP OSL_HOSTDEVICE int
osl_hash_if (float x)
{
return inthashf (x);
}
OSL_SHADEOP int
OSL_SHADEOP OSL_HOSTDEVICE int
osl_hash_iff (float x, float y)
{
return inthashf (x, y);
}
OSL_SHADEOP int
osl_hash_iv (float *x)
OSL_SHADEOP OSL_HOSTDEVICE int
osl_hash_iv (void *x)
{
return inthashf (x);
return inthashf (static_cast<float*>(x));
}
OSL_SHADEOP int
osl_hash_ivf (float *x, float y)
OSL_SHADEOP OSL_HOSTDEVICE int
osl_hash_ivf (void *x, float y)
{
return inthashf (x, y);
return inthashf (static_cast<float*>(x), y);
}
+11 -18
View File
@@ -259,7 +259,7 @@ osl_texture (void *sg_, const char *name, void *handle,
// and ensure that they're being put in aligned memory.
OIIO::simd::float4 result_simd, dresultds_simd, dresultdt_simd;
bool ok = sg->renderer->texture (USTR(name),
(TextureSystem::TextureHandle *)handle, NULL,
(TextureSystem::TextureHandle *)handle, sg->context->texture_thread_info(),
*opt, sg, s, t, dsdx, dtdx, dsdy, dtdy, 4,
(float *)&result_simd,
derivs ? (float *)&dresultds_simd : NULL,
@@ -294,18 +294,15 @@ osl_texture (void *sg_, const char *name, void *handle,
OSL_SHADEOP int
osl_texture3d (void *sg_, const char *name, void *handle,
void *opt_, void *P_,
void *dPdx_, void *dPdy_, void *dPdz_, int chans,
void *result, void *dresultdx,
void *dresultdy, void *dresultdz,
void *alpha, void *dalphadx,
void *dalphady, void *dalphadz,
void *opt_, void *P_, void *dPdx_, void *dPdy_,
int chans,
void *result, void *dresultdx, void *dresultdy,
void *alpha , void *dalphadx , void *dalphady ,
ustring *errormessage)
{
const Vec3 &P (*(Vec3 *)P_);
const Vec3 &dPdx (*(Vec3 *)dPdx_);
const Vec3 &dPdy (*(Vec3 *)dPdy_);
const Vec3 &dPdz (*(Vec3 *)dPdz_);
ShaderGlobals *sg = (ShaderGlobals *)sg_;
TextureOpt *opt = (TextureOpt *)opt_;
bool derivs = (dresultdx != NULL || dalphadx != NULL);
@@ -313,12 +310,12 @@ osl_texture3d (void *sg_, const char *name, void *handle,
// and ensure that they're being put in aligned memory.
OIIO::simd::float4 result_simd, dresultds_simd, dresultdt_simd, dresultdr_simd;
bool ok = sg->renderer->texture3d (USTR(name),
(TextureSystem::TextureHandle *)handle, NULL,
*opt, sg, P, dPdx, dPdy, dPdz,
(TextureSystem::TextureHandle *)handle, sg->context->texture_thread_info(),
*opt, sg, P, dPdx, dPdy, Vec3(0),
4, (float *)&result_simd,
derivs ? (float *)&dresultds_simd : NULL,
derivs ? (float *)&dresultdt_simd : NULL,
derivs ? (float *)&dresultdr_simd : NULL,
derivs ? (float *)&dresultds_simd : nullptr,
derivs ? (float *)&dresultdt_simd : nullptr,
derivs ? (float *)&dresultdr_simd : nullptr,
errormessage);
for (int i = 0; i < chans; ++i)
@@ -330,19 +327,15 @@ osl_texture3d (void *sg_, const char *name, void *handle,
if (derivs) {
OIIO::simd::float4 dresultdx_simd = dresultds_simd * dPdx[0] + dresultdt_simd * dPdx[1] + dresultdr_simd * dPdx[2];
OIIO::simd::float4 dresultdy_simd = dresultds_simd * dPdy[0] + dresultdt_simd * dPdy[1] + dresultdr_simd * dPdy[2];
OIIO::simd::float4 dresultdz_simd = dresultds_simd * dPdz[0] + dresultdt_simd * dPdz[1] + dresultdr_simd * dPdz[2];
if (dresultdx) {
for (int i = 0; i < chans; ++i)
((float *)dresultdx)[i] = dresultdx_simd[i];
for (int i = 0; i < chans; ++i)
((float *)dresultdy)[i] = dresultdy_simd[i];
for (int i = 0; i < chans; ++i)
((float *)dresultdz)[i] = dresultdz_simd[i];
}
if (dalphadx) {
((float *)dalphadx)[0] = dresultdx_simd[chans];
((float *)dalphady)[0] = dresultdy_simd[chans];
((float *)dalphadz)[0] = dresultdz_simd[chans];
}
}
@@ -371,7 +364,7 @@ osl_environment (void *sg_, const char *name, void *handle,
OIIO::simd::float4 local_result;
bool ok = sg->renderer->environment (USTR(name),
(TextureSystem::TextureHandle *)handle,
NULL, *opt, sg, R, dRdx, dRdy, 4,
sg->context->texture_thread_info(), *opt, sg, R, dRdx, dRdy, 4,
(float *)&local_result, NULL, NULL,
errormessage);
+11 -35
View File
@@ -48,11 +48,11 @@ string_view
shadertypename (ShaderType s)
{
switch (s) {
case ShadTypeGeneric: return ("shader");
case ShadTypeSurface: return ("surface");
case ShadTypeDisplacement: return ("displacement");
case ShadTypeVolume: return ("volume");
case ShadTypeLight: return ("light");
case ShaderType::Generic : return ("shader");
case ShaderType::Surface : return ("surface");
case ShaderType::Displacement : return ("displacement");
case ShaderType::Volume : return ("volume");
case ShaderType::Light : return ("light");
default:
ASSERT (0 && "Invalid shader type");
}
@@ -64,40 +64,16 @@ ShaderType
shadertype_from_name (string_view name)
{
if (name == "shader" || name == "generic")
return ShadTypeGeneric;
return ShaderType::Generic;
if (name == "surface")
return ShadTypeSurface;
return ShaderType::Surface;
if (name == "displacement")
return ShadTypeDisplacement;
return ShaderType::Displacement;
if (name == "volume")
return ShadTypeVolume;
return ShaderType::Volume;
if (name == "light")
return ShadTypeLight;
return ShadTypeUnknown;
}
const char *
shaderusename (ShaderUse s)
{
switch (s) {
case ShadUseSurface: return ("surface");
case ShadUseDisplacement: return ("displacement");
default:
ASSERT (0 && "Invalid shader use");
}
}
ShaderUse
shaderuse_from_name (string_view name)
{
if (name == "surface")
return ShadUseSurface;
if (name == "displacement")
return ShadUseDisplacement;
return ShadUseLast;
return ShaderType::Light;
return ShaderType::Unknown;
}
+72 -63
View File
@@ -39,6 +39,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/thread/tss.hpp> /* for thread_specific_ptr */
// Pull in the modified Imath headers and the OSL_HOSTDEVICE macro
#ifdef __CUDACC__
#include <OSL/oslconfig.h>
#endif
#include <OpenImageIO/ustring.h>
#include <OpenImageIO/thread.h>
#include <OpenImageIO/paramlist.h>
@@ -191,14 +196,20 @@ expand (std::vector<T> &vec, size_t size)
// Struct to hold records about what user data a group needs
struct UserDataNeeded {
ustring name;
int layer_num;
TypeDesc type;
void* data;
bool derivs;
UserDataNeeded (ustring name, TypeDesc type, bool derivs=false)
: name(name), type(type), derivs(derivs) {}
UserDataNeeded (ustring name, int layer_num, TypeDesc type, void* data=NULL,
bool derivs=false)
: name(name), layer_num(layer_num), type(type), data(data),
derivs(derivs) {}
friend bool operator< (const UserDataNeeded &a, const UserDataNeeded &b) {
if (a.name != b.name)
return a.name < b.name;
if (a.layer_num != b.layer_num )
return a.layer_num < b.layer_num;
if (a.type.basetype != b.type.basetype)
return a.type.basetype < b.type.basetype;
if (a.type.aggregate != b.type.aggregate)
@@ -506,9 +517,8 @@ public:
bool Parameter (string_view name, TypeDesc t, const void *val);
bool Parameter (string_view name, TypeDesc t, const void *val,
bool lockgeom);
bool Shader (string_view shaderusage,
string_view shadername = string_view(),
string_view layername = string_view());
bool Shader (string_view shaderusage, string_view shadername,
string_view layername);
ShaderGroupRef ShaderGroupBegin (string_view groupname = string_view());
bool ShaderGroupEnd (void);
bool ConnectShaders (string_view srclayer, string_view srcparam,
@@ -522,7 +532,6 @@ public:
// Internal error, warning, info, and message reporting routines that
// take printf-like arguments.
#if OIIO_VERSION >= 10803
template<typename T1, typename... Args>
inline void error (string_view fmt, const T1& v1, const Args&... args) const {
error (Strutil::format (fmt, v1, args...));
@@ -546,20 +555,6 @@ public:
message (Strutil::format (fmt, v1, args...));
}
void message (const std::string &message) const;
#else
TINYFORMAT_WRAP_FORMAT (void, error, const,
std::ostringstream msg;, msg, error(msg.str());)
TINYFORMAT_WRAP_FORMAT (void, warning, const,
std::ostringstream msg;, msg, warning(msg.str());)
TINYFORMAT_WRAP_FORMAT (void, info, const,
std::ostringstream msg;, msg, info(msg.str());)
TINYFORMAT_WRAP_FORMAT (void, message, const,
std::ostringstream msg;, msg, message(msg.str());)
void error (const std::string &message) const;
void warning (const std::string &message) const;
void info (const std::string &message) const;
void message (const std::string &message) const;
#endif
std::string getstats (int level=1) const;
@@ -609,6 +604,7 @@ public:
int llvm_debug () const { return m_llvm_debug; }
int llvm_debug_layers () const { return m_llvm_debug_layers; }
int llvm_debug_ops () const { return m_llvm_debug_ops; }
int llvm_output_bitcode () const { return m_llvm_output_bitcode; }
bool fold_getattribute () const { return m_opt_fold_getattribute; }
bool opt_texture_handle () const { return m_opt_texture_handle; }
int opt_passes() const { return m_opt_passes; }
@@ -620,6 +616,7 @@ public:
bool no_noise() const { return m_no_noise; }
bool no_pointcloud() const { return m_no_pointcloud; }
bool force_derivs() const { return m_force_derivs; }
bool allow_shader_replacement() const { return m_allow_shader_replacement; }
ustring commonspace_synonym () const { return m_commonspace_synonym; }
ustring debug_groupname() const { return m_debug_groupname; }
@@ -633,7 +630,7 @@ public:
/// The group is set and won't be changed again; take advantage of
/// this by optimizing the code knowing all our instance parameters
/// (at least the ones that can't be overridden by the geometry).
void optimize_group (ShaderGroup &group);
void optimize_group (ShaderGroup &group, ShadingContext *ctx = nullptr);
/// After doing all optimization and code JIT, we can clean up by
/// deleting the instances' code and arguments, and paring their
@@ -758,6 +755,9 @@ private:
OpDescriptorMap m_op_descriptor;
// Pre-compiled support library
std::vector<char> m_lib_bitcode; ///> Container for the pre-compiled library bitcode
// Options
int m_statslevel; ///< Statistics level
bool m_lazylayers; ///< Evaluate layers on demand?
@@ -770,6 +770,7 @@ private:
bool m_debug_uninit; ///< Find use of uninitialized vars?
bool m_lockgeom_default; ///< Default value of lockgeom
bool m_strict_messages; ///< Strict checking of message passing usage?
bool m_error_repeats; ///< Allow repeats of identical err/warn?
bool m_range_checking; ///< Range check arrays & components?
bool m_unknown_coordsys_error; ///< Error to use unknown xform name?
bool m_connection_error; ///< Error for ConnectShaders to fail?
@@ -801,6 +802,7 @@ private:
int m_llvm_debug; ///< More LLVM debugging output
int m_llvm_debug_layers; ///< Add layer enter/exit printfs
int m_llvm_debug_ops; ///< Add printfs to every op
int m_llvm_output_bitcode; ///< Output bitcode for each group
ustring m_debug_groupname; ///< Name of sole group to debug
ustring m_debug_layername; ///< Name of sole layer to debug
ustring m_opt_layername; ///< Name of sole layer to optimize
@@ -819,6 +821,7 @@ private:
bool m_no_noise; ///< Substitute trivial noise calls
bool m_no_pointcloud; ///< Substitute trivial pointcloud calls
bool m_force_derivs; ///< Force derivs on everything
bool m_allow_shader_replacement; ///< Allow shader masters to replace
int m_exec_repeat; ///< How many times to execute group
// Derived/cached calculations from options:
@@ -832,7 +835,7 @@ private:
// State
bool m_in_group; ///< Are we specifying a group?
ShaderUse m_group_use; ///< Use of group
std::string m_group_use; ///< "Use" of group
ParamValueList m_pending_params; ///< Pending Parameter() values
ShaderGroupRef m_curgroup; ///< Current shading attribute state
mutable mutex m_mutex; ///< Thread safety
@@ -946,6 +949,9 @@ struct ConnectedParam {
bool is_complete () const {
return arrayindex == -1 && channel == -1;
}
// Debug output of ConnectedParam
std::string str (const ShaderInstance *inst);
};
@@ -967,6 +973,12 @@ struct Connection {
bool operator!= (const Connection &c) const {
return srclayer != c.srclayer || src != c.src || dst != c.dst;
}
// Does the connection fully join the source and destination.
bool is_complete () const { return src.is_complete() && dst.is_complete(); }
// Debug output of ConnectedParam
std::string str (const ShaderGroup &group, const ShaderInstance *dstinst);
};
@@ -1312,6 +1324,13 @@ public:
m_current_block = 0;
}
// avoid 'attempting to reference a deleted function' of std::unique_ptr<char>s
// in reference to those member variables of ShadingContext
SimplePool(const SimplePool &) = delete;
SimplePool(SimplePool &&) = delete;
SimplePool &operator=(const SimplePool &) = delete;
SimplePool &&operator=(SimplePool &&) = delete;
~SimplePool() {}
char * alloc(size_t size, size_t alignment=1) {
@@ -1543,36 +1562,43 @@ private:
// Put all the things that are read-only (after optimization) and
// needed on every shade execution at the front of the struct, as much
// together on one cache line as possible.
volatile int m_optimized; ///< Is it already optimized?
bool m_does_nothing; ///< Is the shading group just func() { return; }
size_t m_llvm_groupdata_size; ///< Heap size needed for its groupdata
volatile int m_optimized = 0; ///< Is it already optimized?
bool m_does_nothing = false; ///< Is the shading group just func() { return; }
size_t m_llvm_groupdata_size = 0;///< Heap size needed for its groupdata
int m_id; ///< Unique ID for the group
int m_num_entry_layers; ///< Number of marked entry layers
RunLLVMGroupFunc m_llvm_compiled_version;
RunLLVMGroupFunc m_llvm_compiled_init;
int m_num_entry_layers = 0; ///< Number of marked entry layers
RunLLVMGroupFunc m_llvm_compiled_version = nullptr;
RunLLVMGroupFunc m_llvm_compiled_init = nullptr;
std::vector<RunLLVMGroupFunc> m_llvm_compiled_layers;
std::vector<ShaderInstanceRef> m_layers;
ustring m_name;
int m_exec_repeat; ///< How many times to execute group
int m_raytype_queries; ///< Bitmask of raytypes queried
int m_raytypes_on; ///< Bitmask of raytypes we assume to be on
int m_raytypes_off; ///< Bitmask of raytypes we assume to be off
int m_exec_repeat = 1; ///< How many times to execute group
int m_raytype_queries = -1; ///< Bitmask of raytypes queried
int m_raytypes_on = 0; ///< Bitmask of raytypes we assume to be on
int m_raytypes_off = 0; ///< Bitmask of raytypes we assume to be off
mutable mutex m_mutex; ///< Thread-safe optimization
int m_globals_read = 0;
int m_globals_write = 0;
std::vector<ustring> m_textures_needed;
std::vector<ustring> m_closures_needed;
std::vector<ustring> m_globals_needed;
std::vector<ustring> m_globals_needed; // semi-deprecated
std::vector<ustring> m_userdata_names;
std::vector<TypeDesc> m_userdata_types;
std::vector<int> m_userdata_offsets;
std::vector<char> m_userdata_derivs;
std::vector<int> m_userdata_layers;
std::vector<void*> m_userdata_init_vals;
std::vector<ustring> m_attributes_needed;
std::vector<ustring> m_attribute_scopes;
std::vector<ustring> m_renderer_outputs; ///< Names of renderer outputs
bool m_unknown_textures_needed;
bool m_unknown_closures_needed;
bool m_unknown_attributes_needed;
atomic_ll m_executions; ///< Number of times the group executed
atomic_ll m_stat_total_shading_time_ticks; ///< Total shading time (ticks)
atomic_ll m_executions {0}; ///< Number of times the group executed
atomic_ll m_stat_total_shading_time_ticks {0}; ///< Total shading time (ticks)
// PTX assembly for compiled ShaderGroup
std::string m_llvm_ptx_compiled_version;
friend class OSL::pvt::ShadingSystemImpl;
friend class OSL::pvt::BackendLLVM;
@@ -1614,7 +1640,7 @@ public:
ClosureComponent * closure_component_allot(int id, size_t prim_size, const Color3 &w) {
// Allocate the component and the mul back to back
size_t needed = sizeof(ClosureComponent) - sizeof(void*) + prim_size;
size_t needed = sizeof(ClosureComponent) + prim_size;
ClosureComponent *comp = (ClosureComponent *) m_closure_pool.alloc(needed, alignof(ClosureComponent));
comp->id = id;
comp->w = w;
@@ -1687,10 +1713,6 @@ public:
/// attribname is "", return the value of the node itself.
int dict_value (int nodeID, ustring attribname, TypeDesc type, void *data);
/// Various setup of the context done by execute(). Return true if
/// the function should be executed, otherwise false.
bool prepare_execution (ShaderUse use, ShaderGroup &sas);
bool osl_get_attribute (ShaderGlobals *sg, void *objdata, int dest_derivs,
ustring obj_name, ustring attr_name,
int array_lookup, int index,
@@ -1760,7 +1782,6 @@ public:
// Process all the recorded errors, warnings, printfs
void process_errors () const;
#if OIIO_VERSION >= 10803
template<typename... Args>
inline void error (string_view fmt, const Args&... args) const {
record_error(ErrorHandler::EH_ERROR, Strutil::format (fmt, args...));
@@ -1780,20 +1801,6 @@ public:
inline void message (string_view fmt, const Args&... args) const {
record_error(ErrorHandler::EH_MESSAGE, Strutil::format (fmt, args...));
}
#else
TINYFORMAT_WRAP_FORMAT (void, error, const,
std::ostringstream msg;, msg,
record_error(ErrorHandler::EH_ERROR, msg.str());)
TINYFORMAT_WRAP_FORMAT (void, warning, const,
std::ostringstream msg;, msg,
record_error(ErrorHandler::EH_WARNING, msg.str());)
TINYFORMAT_WRAP_FORMAT (void, info, const,
std::ostringstream msg;, msg,
record_error(ErrorHandler::EH_INFO, msg.str());)
TINYFORMAT_WRAP_FORMAT (void, message, const,
std::ostringstream msg;, msg,
record_error(ErrorHandler::EH_MESSAGE, msg.str());)
#endif
private:
@@ -1845,14 +1852,6 @@ private:
// Buffering of error messages and printfs
typedef std::pair<ErrorHandler::ErrCode, std::string> ErrorItem;
mutable std::vector<ErrorItem> m_buffered_errors;
// Calculate offset needed to align ClosureComponent's mem to a given alignment.
inline size_t closure_alignment_offset_calc(size_t alignment) {
return alignment == 1
? 0
: alignment - (reckless_offsetof(ClosureComponent, mem) & (alignment - 1));
}
};
@@ -1996,6 +1995,16 @@ public:
return m_bblockids[opnum];
}
// Mangle the group and layer into a unique function name
std::string layer_function_name (const ShaderGroup &group,
const ShaderInstance &inst) {
return Strutil::format ("%s_%s_%d", group.name(),
inst.layername(), inst.id());
}
std::string layer_function_name () {
return layer_function_name (group(), *inst());
}
protected:
ShadingSystemImpl &m_shadingsys; ///< Backpointer to shading system
ShaderGroup &m_group; ///< Group we're processing
+6
View File
@@ -117,6 +117,12 @@ using namespace OSL::pvt;
#define isatty _isatty
#endif
// flex itself will generate fatal warnings about signed vs unsigned.
// Bypass that nonsense.
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 6
#pragma GCC diagnostic ignored "-Wsign-compare"
#endif
%}
/* Declare modes */
+4 -4
View File
@@ -91,7 +91,7 @@ struct SortedPointCompare {
PointCloud *
PointCloud::get (ustring filename, bool write)
{
if (! filename)
if (filename.empty())
return NULL;
spin_lock lock (pointcloudmap_mutex);
PointCloudMap::const_iterator found = pointclouds.find(filename);
@@ -139,7 +139,7 @@ PointCloud::PointCloud (ustring filename,
PointCloud::~PointCloud ()
{
// Save the file if we wrote to it
if (m_write && m_filename)
if (m_write && !m_filename.empty())
Partio::write (m_filename.c_str(), *m_partio_cloud);
if (m_partio_cloud)
m_partio_cloud->release ();
@@ -238,7 +238,7 @@ RendererServices::pointcloud_search (ShaderGlobals *sg,
float *out_distances, int derivs_offset)
{
#if USE_PARTIO
if (! filename)
if (filename.empty())
return 0;
PointCloud *pc = PointCloud::get(filename);
if (pc == NULL) { // The file failed to load
@@ -408,7 +408,7 @@ RendererServices::pointcloud_write (ShaderGlobals *sg,
const void **data)
{
#if USE_PARTIO
if (! filename)
if (filename.empty())
return false;
PointCloud *pc = PointCloud::get(filename, true /* create file to write */);
spin_lock lock (pc->m_mutex);
+3 -3
View File
@@ -184,7 +184,7 @@ RendererServices::texture (ustring filename, TextureHandle *texture_handle,
// Deprecated version
// Deprecated version (1.8)
bool
RendererServices::texture (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
@@ -256,7 +256,7 @@ RendererServices::texture3d (ustring filename, TextureHandle *texture_handle,
// Deprecated version
// Deprecated version (1.8)
bool
RendererServices::texture3d (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
@@ -327,7 +327,7 @@ RendererServices::environment (ustring filename, TextureHandle *texture_handle,
// Deprecated version
// Deprecated version (1.8)
bool
RendererServices::environment (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
+41 -13
View File
@@ -125,7 +125,7 @@ RuntimeOptimizer::RuntimeOptimizer (ShadingSystemImpl &shadingsys,
m_stop_optimizing(false),
m_raytypes_on(group.raytypes_on()), m_raytypes_off(group.raytypes_off())
{
memset (&m_shaderglobals, 0, sizeof(ShaderGlobals));
memset ((char *)&m_shaderglobals, 0, sizeof(ShaderGlobals));
m_shaderglobals.context = shadingcontext();
}
@@ -169,15 +169,15 @@ OSOProcessorBase::set_debug ()
// If either group or layer was specified for debug, surely they want
// debugging turned on.
if (shadingsys().debug_groupname() || shadingsys().debug_layername())
if (!shadingsys().debug_groupname().empty() || !shadingsys().debug_layername().empty())
m_debug = std::max (m_debug, 1);
// Force debugging off if a specific group was selected for debug
// and we're not it, or a specific layer was selected for debug and
// we're not it.
bool wronggroup = (shadingsys().debug_groupname() &&
bool wronggroup = (!shadingsys().debug_groupname().empty() &&
shadingsys().debug_groupname() != group().name());
bool wronglayer = (shadingsys().debug_layername() && inst() &&
bool wronglayer = (!shadingsys().debug_layername().empty() && inst() &&
shadingsys().debug_layername() != inst()->layername());
if (wronggroup || wronglayer)
m_debug = 0;
@@ -192,7 +192,7 @@ RuntimeOptimizer::set_debug ()
// If a specific group is isolated for debugging and the
// 'optimize_dondebug' flag is on, fully optimize all other groups.
if (shadingsys().debug_groupname() &&
if (!shadingsys().debug_groupname().empty() &&
shadingsys().debug_groupname() != group().name()) {
if (shadingsys().m_optimize_nondebug) {
// Debugging trick: if user said to only debug one group, turn
@@ -921,12 +921,19 @@ RuntimeOptimizer::simplify_params ()
// It's connected to an earlier layer. If the output var of
// the upstream shader is effectively constant or a global,
// then so is this variable.
turn_into_nop (s->initbegin(), s->initend(),
"connected value doesn't need init ops");
for (auto&& c : inst()->connections()) {
if (c.dst.param == i) {
if (c.dst.param != i)
continue;
if (c.dst.is_complete()) {
/// All components are being set through either
/// float->triple or triple->triple
/// Get rid of the un-needed init ops.
turn_into_nop (s->initbegin(), s->initend(),
"connected value doesn't need init ops");
}
if (c.is_complete()) {
// srcsym is the earlier group's output param, which
// is connected as the input to the param we're
// is fully connected as the input to the param we're
// examining.
ShaderInstance *uplayer = group()[c.srclayer];
Symbol *srcsym = uplayer->symbol(c.src.param);
@@ -938,8 +945,7 @@ RuntimeOptimizer::simplify_params ()
// If so, make sure the global is in this instance's
// symbol table, and alias the parameter to it.
ustringmap_t &g (m_params_holding_globals[c.srclayer]);
ustringmap_t::const_iterator f;
f = g.find (srcsym->name());
auto f = g.find (srcsym->name());
if (f != g.end()) {
if (debug() > 1)
debug_opt ("Remapping %s.%s because it's connected to "
@@ -972,6 +978,20 @@ RuntimeOptimizer::simplify_params ()
}
}
}
// FIXME / N.B.: We only optimize "fully complete" connections,
// not those involving individual components or array elements
// of the connected parameters, because we sure don't track the
// constness or aliasing of individual components/element, only
// whole variables. But there are two cases where the logic
// above fails to fully exploit the connection propagating a
// constant value. (a) Partial-to-whole connections, for example
// connecting one component of an upstream triple output to a
// downstream float input, should propagate the constant, but we
// currently neglect this case. (b) If *multiple* conections
// combine to fully propagate values, for example if someone was
// foolish enough to connect R, G, and B components of color
// parameters *separately*, we sure don't notice that and treat
// it as a full connection of the color.
}
}
}
@@ -2250,7 +2270,7 @@ void
RuntimeOptimizer::optimize_instance ()
{
// If "opt_layername" attribute is set, only optimize the named layer
if (shadingsys().m_opt_layername &&
if (!shadingsys().m_opt_layername.empty() &&
shadingsys().m_opt_layername != inst()->layername())
return;
@@ -3129,6 +3149,8 @@ RuntimeOptimizer::run ()
m_unknown_attributes_needed = false;
m_textures_needed.clear();
m_closures_needed.clear();
m_globals_read = 0;
m_globals_write = 0;
m_globals_needed.clear();
m_userdata_needed.clear();
m_attributes_needed.clear();
@@ -3143,7 +3165,8 @@ RuntimeOptimizer::run ()
// Find interpolated parameters
if ((s.symtype() == SymTypeParam || s.symtype() == SymTypeOutputParam)
&& ! s.lockgeom()) {
UserDataNeeded udn (s.name(), s.typespec().simpletype(), s.has_derivs());
UserDataNeeded udn (s.name(), layer, s.typespec().simpletype(),
s.data(), s.has_derivs());
std::set<UserDataNeeded>::iterator found;
found = m_userdata_needed.find (udn);
if (found == m_userdata_needed.end())
@@ -3156,6 +3179,11 @@ RuntimeOptimizer::run ()
// Track which globals the group needs
if (s.symtype() == SymTypeGlobal) {
m_globals_needed.insert (s.name());
int bit = int(ShadingSystem::globals_bit (s.name()));
if (s.everread())
m_globals_read |= bit;
if (s.everwritten())
m_globals_write |= bit;
}
if (s.has_derivs())
++new_deriv_syms;
+3 -6
View File
@@ -154,16 +154,11 @@ public:
int turn_into_nop (int begin, int end, string_view why=NULL);
void debug_opt_impl (string_view message) const;
#if OIIO_VERSION >= 10803
template<typename... Args>
inline void debug_opt (string_view fmt, const Args&... args) const {
debug_opt_impl (Strutil::format (fmt, args...));
}
#else
TINYFORMAT_WRAP_FORMAT (void, debug_opt, const,
std::ostringstream msg;, msg,
debug_opt_impl(msg.str());)
#endif
void debug_opt_ops (int opbegin, int opend, string_view message) const;
void debug_turn_into (const Opcode &op, int numops,
@@ -447,6 +442,8 @@ private:
std::set<ustring> m_textures_needed;
std::set<ustring> m_closures_needed;
std::set<ustring> m_globals_needed;
int m_globals_read = 0;
int m_globals_write = 0;
std::set<AttributeNeeded> m_attributes_needed;
bool m_unknown_textures_needed;
bool m_unknown_closures_needed;
+4 -3
View File
@@ -1,14 +1,15 @@
#!/bin/bash
#!/usr/bin/env bash
# Turn an LLVM-compiled bitfile into a C++ source file where the compiled
# bitcode is in a huge array.
in=$1
out=$2
prefix=$3
echo "#include <cstddef>" > $out
echo "unsigned char osl_llvm_compiled_ops_block[] = {" >> $out
echo "unsigned char " ${prefix}"_block[] = {" >> $out
hexdump -v -e '"" /1 "0x%02x" ",\n"' $in >> $out
echo "0x00 };" >> $out
echo "size_t osl_llvm_compiled_ops_size = sizeof(osl_llvm_compiled_ops_block)-1;" >> $out
echo "size_t " ${prefix}"_size = sizeof("${prefix}"_block)-1;" >> $out
+10 -25
View File
@@ -26,13 +26,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <vector>
#include <string>
#include <cstdio>
#include <fstream>
#include <cstdlib>
#include <functional>
#include <OpenImageIO/dassert.h>
#include <OpenImageIO/thread.h>
#include <OpenImageIO/imagebuf.h>
@@ -51,16 +44,18 @@ using namespace OSL::pvt;
OSL_NAMESPACE_ENTER
bool
shade_image (ShadingSystem &shadingsys, ShaderGroup &group,
const ShaderGlobals *defaultsg,
OIIO::ImageBuf &buf, OIIO::array_view<ustring> outputs,
ShadeImageLocations shadelocations,
OIIO::ROI roi, int nthreads)
OIIO::ROI roi, OIIO::ImageBufAlgo::parallel_image_options popt)
{
using namespace OIIO;
using namespace ImageBufAlgo;
if (! roi.defined())
roi = buf.roi();
// std::cout << "shade_image " << roi << "\n";
if (buf.spec().format != TypeDesc::FLOAT) {
buf.error ("Cannot OSL::shade_image() into a %f buffer, float is required",
buf.spec().format);
@@ -68,18 +63,7 @@ shade_image (ShadingSystem &shadingsys, ShaderGroup &group,
}
shadingsys.optimize_group (&group);
if (nthreads != 1 && roi.npixels() >= 64*64) {
// Parallelize
OIIO::ImageBufAlgo::parallel_image (
std::bind (shade_image, std::ref(shadingsys),
std::ref(group), defaultsg,
std::ref(buf), outputs, shadelocations,
std::placeholders::_1 /*roi*/, 1 /*nthreads*/),
roi, nthreads);
return true;
}
// Serial case
parallel_image (roi, popt, [&](OIIO::ROI roi){
// Optional: high-performance apps may request this thread-specific
// pointer in order to save a bit of time on each shade. Just like
@@ -110,7 +94,7 @@ shade_image (ShadingSystem &shadingsys, ShaderGroup &group,
const ShaderSymbol **output_sym = OIIO_ALLOCA(const ShaderSymbol*, outputs.size());
TypeDesc *output_type = OIIO_ALLOCA(TypeDesc, outputs.size());
int *output_nchans = OIIO_ALLOCA(int, outputs.size());
for (size_t i = 0; i < outputs.size(); ++i) {
for (int i = 0; i < int(outputs.size()); ++i) {
output_sym[i] = shadingsys.find_symbol (group, outputs[i]);
output_type[i] = shadingsys.symbol_typedesc (output_sym[i]);
output_nchans[i] = output_type[i].numelements() * output_type[i].aggregate;
@@ -127,10 +111,10 @@ shade_image (ShadingSystem &shadingsys, ShaderGroup &group,
if (defaultsg) {
// If the caller passed a default SG template, use it to initialize
// the sg and in particular to set all the constant fields.
memcpy (&sg, defaultsg, sizeof(ShaderGlobals));
memcpy ((char *)&sg, (const char*)defaultsg, sizeof(ShaderGlobals));
} else {
// No SG template was passed, so set up reasonable defaults.
memset (&sg, 0, sizeof(ShaderGlobals));
memset ((char *)&sg, 0, sizeof(ShaderGlobals));
// Set "shader" space to be Mshad. In a real renderer, this may be
// different for each shader group.
sg.shader2common = OSL::TransformationPtr (&Mshad);
@@ -185,7 +169,7 @@ shade_image (ShadingSystem &shadingsys, ShaderGroup &group,
// Save all the designated outputs.
int chan = 0;
for (size_t i = 0; i < outputs.size(); ++i) {
for (int i = 0; i < int(outputs.size()); ++i) {
const void *data = shadingsys.symbol_address (*ctx, output_sym[i]);
if (!data)
continue; // Skip if symbol isn't found
@@ -213,6 +197,7 @@ shade_image (ShadingSystem &shadingsys, ShaderGroup &group,
// destroy it when done with it.
shadingsys.destroy_thread_info (thread_info);
}); // end of parallel_image
return true;
}
+216 -38
View File
@@ -49,9 +49,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace OSL;
using namespace OSL::pvt;
// avoid naming conflict with MSVC macro
#ifdef RGB
#undef RGB
// avoid naming conflicts with MSVC macros
#ifdef _MSC_VER
#undef RGB
// We use some of the iso646.h macro names later on in this file. For
// some compilers (MSVS, I'm looking at you) this is trouble. I don't know
// how or why that header would have been included here, but it did for at
// least one person, so shut off those macros so they don't cause trouble.
#undef and
#undef or
#undef xor
#undef compl
#undef bitand
#undef bitor
#endif
OSL_NAMESPACE_ENTER
@@ -237,15 +247,6 @@ ShadingSystem::execute (ShadingContext *ctx, ShaderGroup &group,
bool
ShadingSystem::execute (ShadingContext &ctx, ShaderGroup &group,
ShaderGlobals &globals, bool run)
{
return m_impl->execute (&ctx, group, globals, run);
}
bool
ShadingSystem::execute_init (ShadingContext &ctx, ShaderGroup &group,
ShaderGlobals &globals, bool run)
@@ -404,6 +405,53 @@ ShadingSystem::query_closure (const char **name, int *id,
static cspan< std::pair<ustring,SGBits> >
sgbit_table ()
{
static const std::pair<ustring,SGBits> table[] = {
{ ustring("P"), SGBits::P },
{ ustring("I"), SGBits::I },
{ ustring("N"), SGBits::N },
{ ustring("Ng"), SGBits::Ng },
{ ustring("u"), SGBits::u },
{ ustring("v"), SGBits::v },
{ ustring("dPdu"), SGBits::dPdu },
{ ustring("dPdv"), SGBits::dPdv },
{ ustring("time"), SGBits::time },
{ ustring("dtime"), SGBits::dtime },
{ ustring("dPdtime"), SGBits::dPdtime },
{ ustring("Ps"), SGBits::Ps },
{ ustring("Ci"), SGBits::Ci }
};
return cspan<std::pair<ustring,SGBits>>(table);
}
SGBits
ShadingSystem::globals_bit (ustring name)
{
for (auto t : sgbit_table()) {
if (name == t.first)
return t.second;
}
return SGBits::None;
}
ustring
ShadingSystem::globals_name (SGBits bit)
{
for (auto t : sgbit_table()) {
if (bit == t.second)
return t.first;
}
return ustring();
}
int
ShadingSystem::raytype_bit (ustring name)
{
@@ -452,21 +500,22 @@ ShadingSystem::set_raytypes (ShaderGroup *group, int raytypes_on, int raytypes_o
void
ShadingSystem::optimize_group (ShaderGroup *group)
ShadingSystem::optimize_group (ShaderGroup *group, ShadingContext *ctx)
{
DASSERT (group);
m_impl->optimize_group (*group);
m_impl->optimize_group (*group, ctx);
}
void
ShadingSystem::optimize_group (ShaderGroup *group,
int raytypes_on, int raytypes_off)
int raytypes_on, int raytypes_off,
ShadingContext *ctx)
{
// convenience function for backwards compatibility
set_raytypes (group, raytypes_on, raytypes_off);
optimize_group (group);
optimize_group (group, ctx);
}
@@ -648,6 +697,7 @@ ShadingSystemImpl::ShadingSystemImpl (RendererServices *renderer,
m_lazy_userdata(false), m_userdata_isconnected(false),
m_clearmemory (false), m_debugnan (false), m_debug_uninit(false),
m_lockgeom_default (true), m_strict_messages(true),
m_error_repeats(false),
m_range_checking(true),
m_unknown_coordsys_error(true), m_connection_error(true),
m_greedyjit(false), m_countlayerexecs(false),
@@ -669,6 +719,7 @@ ShadingSystemImpl::ShadingSystemImpl (RendererServices *renderer,
m_llvm_optimize(0),
m_debug(0), m_llvm_debug(0),
m_llvm_debug_layers(0), m_llvm_debug_ops(0),
m_llvm_output_bitcode(0),
m_commonspace_synonym("world"),
m_colorspace("Rec709"),
m_max_local_mem_KB(2048),
@@ -677,6 +728,7 @@ ShadingSystemImpl::ShadingSystemImpl (RendererServices *renderer,
m_no_noise(false),
m_no_pointcloud(false),
m_force_derivs(false),
m_allow_shader_replacement(false),
m_exec_repeat(1),
m_in_group (false),
m_stat_opt_locking_time(0), m_stat_specialization_time(0),
@@ -1091,6 +1143,7 @@ ShadingSystemImpl::attribute (string_view name, TypeDesc type,
ATTR_SET ("llvm_debug", int, m_llvm_debug);
ATTR_SET ("llvm_debug_layers", int, m_llvm_debug_layers);
ATTR_SET ("llvm_debug_ops", int, m_llvm_debug_ops);
ATTR_SET ("llvm_output_bitcode", int, m_llvm_output_bitcode);
ATTR_SET ("strict_messages", int, m_strict_messages);
ATTR_SET ("range_checking", int, m_range_checking);
ATTR_SET ("unknown_coordsys_error", int, m_unknown_coordsys_error);
@@ -1105,6 +1158,7 @@ ShadingSystemImpl::attribute (string_view name, TypeDesc type,
ATTR_SET ("no_noise", int, m_no_noise);
ATTR_SET ("no_pointcloud", int, m_no_pointcloud);
ATTR_SET ("force_derivs", int, m_force_derivs);
ATTR_SET ("allow_shader_replacement", int, m_allow_shader_replacement);
ATTR_SET ("exec_repeat", int, m_exec_repeat);
ATTR_SET_STRING ("commonspace", m_commonspace_synonym);
ATTR_SET_STRING ("debug_groupname", m_debug_groupname);
@@ -1142,6 +1196,19 @@ ShadingSystemImpl::attribute (string_view name, TypeDesc type,
m_renderer_outputs.emplace_back(((const char **)val)[i]);
return true;
}
if (name == "lib_bitcode" && type.basetype == TypeDesc::UINT8) {
m_lib_bitcode.clear();
m_lib_bitcode = *static_cast<const std::vector<char>*>(val);
return true;
}
if (name == "error_repeats") {
// Special case: setting error_repeats also clears the "previously
// seen" error and warning lists.
m_errseen.clear();
m_warnseen.clear();
ATTR_SET ("error_repeats", int, m_error_repeats);
}
return false;
#undef ATTR_SET
#undef ATTR_SET_STRING
@@ -1165,6 +1232,7 @@ ShadingSystemImpl::getattribute (string_view name, TypeDesc type,
}
lock_guard guard (m_mutex); // Thread safety
ATTR_DECODE_STRING ("searchpath:shader", m_searchpath);
ATTR_DECODE ("statistics:level", int, m_statslevel);
ATTR_DECODE ("lazylayers", int, m_lazylayers);
@@ -1201,7 +1269,9 @@ ShadingSystemImpl::getattribute (string_view name, TypeDesc type,
ATTR_DECODE ("llvm_debug", int, m_llvm_debug);
ATTR_DECODE ("llvm_debug_layers", int, m_llvm_debug_layers);
ATTR_DECODE ("llvm_debug_ops", int, m_llvm_debug_ops);
ATTR_DECODE ("llvm_output_bitcode", int, m_llvm_output_bitcode);
ATTR_DECODE ("strict_messages", int, m_strict_messages);
ATTR_DECODE ("error_repeats", int, m_error_repeats);
ATTR_DECODE ("range_checking", int, m_range_checking);
ATTR_DECODE ("unknown_coordsys_error", int, m_unknown_coordsys_error);
ATTR_DECODE ("connection_error", int, m_connection_error);
@@ -1223,6 +1293,7 @@ ShadingSystemImpl::getattribute (string_view name, TypeDesc type,
ATTR_DECODE ("no_noise", int, m_no_noise);
ATTR_DECODE ("no_pointcloud", int, m_no_pointcloud);
ATTR_DECODE ("force_derivs", int, m_force_derivs);
ATTR_DECODE ("allow_shader_replacement", int, m_allow_shader_replacement);
ATTR_DECODE ("exec_repeat", int, m_exec_repeat);
ATTR_DECODE ("stat:masters", int, m_stat_shaders_loaded);
@@ -1333,6 +1404,7 @@ ShadingSystemImpl::getattribute (ShaderGroup *group, string_view name,
{
if (! group)
return false;
if (name == "groupname" && type == TypeDesc::TypeString) {
*(ustring *)val = group->name();
return true;
@@ -1379,6 +1451,18 @@ ShadingSystemImpl::getattribute (ShaderGroup *group, string_view name,
((ustring *)val)[i] = ustring();
return true;
}
if (name == "group_init_name" && type.basetype == TypeDesc::STRING) {
*(ustring *)val = ustring::format ("group_%d_init", group->id());
return true;
}
if (name == "group_entry_name" && type.basetype == TypeDesc::STRING) {
int nlayers = group->nlayers ();
ShaderInstance *inst = (*group)[nlayers-1];
// This formuation mirrors OSOProcessorBase::layer_function_name()
*(ustring *)val = ustring::format ("%s_%s_%d", group->name(),
inst->layername(), inst->id());
return true;
}
if (name == "num_textures_needed" && type == TypeDesc::TypeInt) {
if (! group->optimized())
optimize_group (*group);
@@ -1432,6 +1516,18 @@ ShadingSystemImpl::getattribute (ShaderGroup *group, string_view name,
*(ustring **)val = n ? &group->m_globals_needed[0] : NULL;
return true;
}
if (name == "globals_read" && type.basetype == TypeDesc::INT) {
if (! group->optimized())
optimize_group (*group);
*(int *)val = group->m_globals_read;
return true;
}
if (name == "globals_write" && type.basetype == TypeDesc::INT) {
if (! group->optimized())
optimize_group (*group);
*(int *)val = group->m_globals_write;
return true;
}
if (name == "num_userdata" && type == TypeDesc::TypeInt) {
if (! group->optimized())
@@ -1503,6 +1599,39 @@ ShadingSystemImpl::getattribute (ShaderGroup *group, string_view name,
return true;
}
// Additional atttributes useful to OptiX-based renderers
if (name == "userdata_layers" && type.basetype == TypeDesc::PTR) {
if (! group->optimized())
optimize_group (*group);
size_t n = group->m_userdata_layers.size();
*(int **)val = n ? &group->m_userdata_layers[0] : NULL;
return true;
}
if (name == "userdata_init_vals" && type.basetype == TypeDesc::PTR) {
if (! group->optimized())
optimize_group (*group);
size_t n = group->m_userdata_init_vals.size();
*(void **)val = n ? &group->m_userdata_init_vals[0] : NULL;
return true;
}
if (name == "ptx_compiled_version" && type.basetype == TypeDesc::PTR) {
bool exists = !group->m_llvm_ptx_compiled_version.empty();
*(std::string *)val = exists ? group->m_llvm_ptx_compiled_version : "";
return true;
}
if (name == "group_id" && type == TypeDesc::TypeInt) {
if (! group->optimized())
optimize_group (*group);
*(int *)val = (int) group->id();
return true;
}
if (name == "layer_osofiles" && type.basetype == TypeDesc::STRING) {
size_t n = std::min (type.numelements(), (size_t)group->nlayers());
for (size_t i = 0; i < n; ++i)
((ustring *)val)[i] =(*group)[i]->master()->osofilename();
return true;
}
return false;
}
@@ -1514,7 +1643,7 @@ ShadingSystemImpl::error (const std::string &msg) const
lock_guard guard (m_errmutex);
int n = 0;
for (auto&& s : m_errseen) {
if (s == msg)
if (s == msg && !m_error_repeats)
return;
++n;
}
@@ -1532,7 +1661,7 @@ ShadingSystemImpl::warning (const std::string &msg) const
lock_guard guard (m_errmutex);
int n = 0;
for (auto&& s : m_warnseen) {
if (s == msg)
if (s == msg && !m_error_repeats)
return;
++n;
}
@@ -1600,8 +1729,8 @@ ShadingSystemImpl::getstats (int level) const
out << "OSL ShadingSystem statistics (" << (void*)this;
out << ") ver " << OSL_LIBRARY_VERSION_STRING
<< ", LLVM " << OSL_LLVM_FULL_VERSION << "\n";
if (m_stat_shaders_requested == 0) {
out << " No shaders requested\n";
if (m_stat_shaders_requested == 0 && m_stat_shaders_loaded == 0) {
out << " No shaders requested or loaded\n";
return out.str();
}
@@ -1616,6 +1745,7 @@ ShadingSystemImpl::getstats (int level) const
INTOPT (llvm_debug);
BOOLOPT (llvm_debug_layers);
BOOLOPT (llvm_debug_ops);
BOOLOPT (llvm_output_bitcode);
BOOLOPT (lazylayers);
BOOLOPT (lazyglobals);
BOOLOPT (lazyunconnected);
@@ -1626,6 +1756,7 @@ ShadingSystemImpl::getstats (int level) const
BOOLOPT (debug_uninit);
BOOLOPT (lockgeom_default);
BOOLOPT (strict_messages);
BOOLOPT (error_repeats);
BOOLOPT (range_checking);
BOOLOPT (greedyjit);
BOOLOPT (countlayerexecs);
@@ -1648,6 +1779,7 @@ ShadingSystemImpl::getstats (int level) const
INTOPT (no_noise);
INTOPT (no_pointcloud);
INTOPT (force_derivs);
INTOPT (allow_shader_replacement);
INTOPT (exec_repeat);
STROPT (debug_groupname);
STROPT (debug_layername);
@@ -1867,7 +1999,7 @@ ShadingSystemImpl::ShaderGroupBegin (string_view groupname)
return ShaderGroupRef();
}
m_in_group = true;
m_group_use = ShadUseUnknown;
m_group_use.clear(); // unknown/unset group
m_curgroup.reset (new ShaderGroup(groupname));
m_curgroup->m_exec_repeat = m_exec_repeat;
return m_curgroup;
@@ -1884,7 +2016,7 @@ ShadingSystemImpl::ShaderGroupEnd (void)
}
// Mark the layers that can be run lazily
if (m_group_use != ShadUseUnknown) {
if (! m_group_use.empty()) {
int nlayers = m_curgroup->nlayers ();
for (int layer = 0; layer < nlayers; ++layer) {
ShaderInstance *inst = (*m_curgroup)[layer];
@@ -1917,7 +2049,7 @@ ShadingSystemImpl::ShaderGroupEnd (void)
}
m_in_group = false;
m_group_use = ShadUseUnknown;
m_group_use.clear(); // Mark use as unset/unknown
ustring groupname = m_curgroup->name();
if (groupname.size() && groupname == m_archive_groupname) {
@@ -1947,27 +2079,34 @@ ShadingSystemImpl::Shader (string_view shaderusage,
return false;
}
ShaderUse use = shaderuse_from_name (shaderusage);
if (use == ShadUseUnknown) {
error ("Unknown shader usage \"%s\"", shaderusage);
if (shaderusage.empty()) {
error ("Shader usage required");
return false;
}
// If a layer name was not supplied, make one up.
std::string local_layername;
if (layername.empty()) {
local_layername = OIIO::Strutil::format ("%s_%d", master->shadername(),
m_curgroup->nlayers());
layername = string_view (local_layername);
}
ShaderInstanceRef instance (new ShaderInstance (master, layername));
instance->parameters (m_pending_params);
m_pending_params.clear ();
if (singleton || m_group_use == ShadUseUnknown) {
if (singleton || m_group_use.empty()) {
// A singleton, or the first in a group
m_curgroup->clear ();
m_stat_groups += 1;
}
if (! singleton) {
if (m_group_use == ShadUseUnknown) { // First shader in group
m_group_use = use;
} else if (use != m_group_use) {
if (m_group_use.empty()) { // First shader in group
m_group_use = shaderusage;
} else if (shaderusage != m_group_use) {
error ("Shader usage \"%s\" does not match current group (%s)",
shaderusage, shaderusename (m_group_use));
shaderusage, m_group_use);
return false;
}
}
@@ -2060,6 +2199,16 @@ ShadingSystemImpl::ConnectShaders (string_view srclayer, string_view srcparam,
return false;
}
const Symbol *dstsym = dstinst->mastersymbol(dstcon.param);
ASSERT (dstsym);
if (dstsym && !dstsym->allowconnect()) {
std::string name = dstlayer.size() ? Strutil::format("%s.%s", dstlayer, dstparam)
: std::string(dstparam);
error ("ConnectShaders: cannot connect to %s because it has metadata allowconnect=0",
name);
return false;
}
dstinst->add_connection (srcinstindex, srccon, dstcon);
dstinst->instoverride(dstcon.param)->valuesource (Symbol::ConnectedVal);
srcinst->instoverride(srccon.param)->connected_down (true);
@@ -2174,7 +2323,7 @@ ShadingSystemImpl::ShaderGroupBegin (string_view groupname,
}
}
string_view paramname (paramname_string);
int lockgeom = true;
int lockgeom = m_lockgeom_default;
// For speed, reserve space. Note that for "unsized" arrays, we only
// preallocate 1 slot and let it grow as needed. That's ok. For
// everything else, we will reserve the right amount up front.
@@ -2363,8 +2512,13 @@ ShadingSystemImpl::ReParameter (ShaderGroup &group, string_view layername_,
int paramindex = layer->findparam (ustring(paramname));
if (paramindex < 0)
return false; // could not find the named parameter
Symbol *sym = layer->symbol (paramindex);
ASSERT (sym != NULL);
if (!sym) {
// Can have a paramindex >= 0, but no symbol when it's a master-symbol
DASSERT(layer->mastersymbol(paramindex) && "No symbol for paramindex");
return false;
}
// Check for mismatch versus previously-declared type
if (!equivalent(sym->typespec(), type))
@@ -2461,7 +2615,7 @@ ShadingSystemImpl::find_named_layer_in_group (ustring layername,
ShaderInstance * &inst)
{
inst = NULL;
if (m_group_use >= ShadUseUnknown)
if (m_group_use.empty())
return -1;
ShaderGroup &group (*m_curgroup);
for (int i = 0; i < group.nlayers(); ++i) {
@@ -2646,7 +2800,7 @@ ShadingSystemImpl::group_post_jit_cleanup (ShaderGroup &group)
void
ShadingSystemImpl::optimize_group (ShaderGroup &group)
ShadingSystemImpl::optimize_group (ShaderGroup &group, ShadingContext *ctx)
{
if (group.optimized())
return; // already optimized
@@ -2664,7 +2818,7 @@ ShadingSystemImpl::optimize_group (ShaderGroup &group)
return;
}
if (m_only_groupname && m_only_groupname != group.name()) {
if (!m_only_groupname.empty() && m_only_groupname != group.name()) {
// For debugging purposes, we are requested to compile only one
// shader group, and this is not it. Mark it as does_nothing,
// and also as optimized so nobody locks on it again, and record
@@ -2680,7 +2834,11 @@ ShadingSystemImpl::optimize_group (ShaderGroup &group)
double locking_time = timer();
ShadingContext *ctx = get_context ();
bool ctx_allocated = false;
if (! ctx) {
ctx = get_context ();
ctx_allocated = true;
}
RuntimeOptimizer rop (*this, group, ctx);
rop.run ();
@@ -2693,15 +2851,21 @@ ShadingSystemImpl::optimize_group (ShaderGroup &group)
group.m_closures_needed.push_back (f);
for (auto&& f : rop.m_globals_needed)
group.m_globals_needed.push_back (f);
group.m_globals_read = rop.m_globals_read;
group.m_globals_write = rop.m_globals_write;
size_t num_userdata = rop.m_userdata_needed.size();
group.m_userdata_names.reserve (num_userdata);
group.m_userdata_types.reserve (num_userdata);
group.m_userdata_offsets.resize (num_userdata, 0);
group.m_userdata_derivs.reserve (num_userdata);
group.m_userdata_layers.reserve (num_userdata);
group.m_userdata_init_vals.reserve (num_userdata);
for (auto&& n : rop.m_userdata_needed) {
group.m_userdata_names.push_back (n.name);
group.m_userdata_types.push_back (n.type);
group.m_userdata_derivs.push_back (n.derivs);
group.m_userdata_layers.push_back (n.layer_num);
group.m_userdata_init_vals.push_back (n.data);
}
group.m_unknown_attributes_needed = rop.m_unknown_attributes_needed;
for (auto&& f : rop.m_attributes_needed) {
@@ -2714,7 +2878,8 @@ ShadingSystemImpl::optimize_group (ShaderGroup &group)
group_post_jit_cleanup (group);
release_context (ctx);
if (ctx_allocated)
release_context (ctx);
group.m_optimized = true;
spin_lock stat_lock (m_stat_mutex);
@@ -3098,6 +3263,19 @@ OSL::OSLQuery::init (const ShaderGroup *group, int layernum)
p.fdefault.clear();
p.sdefault.clear();
p.spacename.clear();
int n = int (p.type.numelements() * p.type.aggregate);
if (p.type.basetype == TypeDesc::INT) {
for (int i = 0; i < n; ++i)
p.idefault.push_back (sym->get_int(i));
}
if (p.type.basetype == TypeDesc::FLOAT) {
for (int i = 0; i < n; ++i)
p.fdefault.push_back (sym->get_float(i));
}
if (p.type.basetype == TypeDesc::STRING) {
for (int i = 0; i < n; ++i)
p.sdefault.push_back (sym->get_string(i));
}
p.fields.clear(); // don't bother filling this out
if (StructSpec *ss = ts.structspec()) {
p.structname = ss->name().string();
+6 -4
View File
@@ -178,22 +178,24 @@ void spline_inverse (const SplineBasis *spline,
int knot_arraylen)
{
// account for out-of-range inputs, just clamp to the values we have
int lowindex = spline->basis_step == 1 ? 1 : 0;
int highindex = spline->basis_step == 1 ? knot_count-2 : knot_count-1;
bool increasing = knots[1] < knots[knot_count-2];
if (increasing) {
if (y <= knots[1]) {
if (y <= knots[lowindex]) {
x = YTYPE(0);
return;
}
if (y >= knots[knot_count-2]) {
if (y >= knots[highindex]) {
x = YTYPE(1);
return;
}
} else {
if (y >= knots[1]) {
if (y >= knots[lowindex]) {
x = YTYPE(0);
return;
}
if (y <= knots[knot_count-2]) {
if (y <= knots[highindex]) {
x = YTYPE(1);
return;
}
+8
View File
@@ -7,6 +7,14 @@ if (BUILDSTATIC)
ADD_LIBRARY ( oslnoise STATIC ${liboslnoise_srcs} )
else ()
ADD_LIBRARY ( oslnoise SHARED ${liboslnoise_srcs} )
if (VERBOSE)
message(STATUS "Setting SOVERSION to: ${SOVERSION}")
endif ()
set_target_properties( oslnoise
PROPERTIES
VERSION ${OSL_VERSION_MAJOR}.${OSL_VERSION_MINOR}.${OSL_VERSION_PATCH}
SOVERSION ${SOVERSION} )
endif ()
TARGET_LINK_LIBRARIES ( oslnoise ${OPENIMAGEIO_LIBRARIES} ${ILMBASE_LIBRARIES} ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} )
+3 -3
View File
@@ -60,9 +60,9 @@ public:
// seed based on the cell containing P
fast_rng (const Vec3 &p, int seed=0) {
// Use guts of cellnoise
unsigned int pi[4] = { unsigned(quick_floor(p[0])),
unsigned(quick_floor(p[1])),
unsigned(quick_floor(p[2])),
unsigned int pi[4] = { unsigned(OIIO::ifloor(p[0])),
unsigned(OIIO::ifloor(p[1])),
unsigned(OIIO::ifloor(p[2])),
unsigned(seed) };
m_seed = inthash<4>(pi);
if (! m_seed)
+79 -67
View File
@@ -29,10 +29,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
#include <OpenImageIO/simd.h>
#include <OpenImageIO/unittest.h>
#include <OpenImageIO/argparse.h>
#include <OpenImageIO/imagebuf.h>
#include <OpenImageIO/timer.h>
#include <OpenImageIO/benchmark.h>
#include <OSL/oslnoise.h>
@@ -98,48 +100,6 @@ inline float abs (const Vec3& a) {
template <typename FUNC, typename T>
void benchmark1 (string_view funcname, FUNC func, T x)
{
auto repeat_func = [&](){
// Unroll the loop 8 times
auto r = func(x); DoNotOptimize (r); clobber_all_memory();
r = func(x); DoNotOptimize (r); clobber_all_memory();
r = func(x); DoNotOptimize (r); clobber_all_memory();
r = func(x); DoNotOptimize (r); clobber_all_memory();
r = func(x); DoNotOptimize (r); clobber_all_memory();
r = func(x); DoNotOptimize (r); clobber_all_memory();
r = func(x); DoNotOptimize (r); clobber_all_memory();
r = func(x); DoNotOptimize (r); clobber_all_memory();
};
float time = time_trial (repeat_func, ntrials, iterations/8);
std::cout << Strutil::format (" %s: %7.1f Mcalls/sec\n",
funcname, (iterations/1.0e6)/time);
}
template <typename FUNC, typename S, typename T>
void benchmark2 (string_view funcname, FUNC func, S x, T y)
{
auto repeat_func = [&](){
// Unroll the loop 8 times
auto r = func(x,y); DoNotOptimize (r); clobber_all_memory();
r = func(x,y); DoNotOptimize (r); clobber_all_memory();
r = func(x,y); DoNotOptimize (r); clobber_all_memory();
r = func(x,y); DoNotOptimize (r); clobber_all_memory();
r = func(x,y); DoNotOptimize (r); clobber_all_memory();
r = func(x,y); DoNotOptimize (r); clobber_all_memory();
r = func(x,y); DoNotOptimize (r); clobber_all_memory();
r = func(x,y); DoNotOptimize (r); clobber_all_memory();
};
float time = time_trial (repeat_func, ntrials, iterations/8);
std::cout << Strutil::format (" %s: %7.1f Mcalls/sec\n",
funcname, (iterations/1.0e6)/time);
}
void
test_perlin ()
{
@@ -214,20 +174,35 @@ test_perlin ()
OIIO_CHECK_EQUAL_THRESH (vs4, vresults_4d[i], eps);
}
#if OPENIMAGEIO_VERSION >= 10904
// Make sure the right thing happens at integer cell boundaries.
// Perlin noise should be continuous everywhere.
OIIO_CHECK_EQUAL_APPROX (noise( 0.9999f), noise( 1.0f));
OIIO_CHECK_EQUAL_APPROX (noise( 1.0001f), noise( 1.0f));
OIIO_CHECK_EQUAL_APPROX (noise(-0.0001f), noise( 0.0f));
OIIO_CHECK_EQUAL_APPROX (noise( 0.0001f), noise( 0.0f));
OIIO_CHECK_EQUAL_APPROX (noise(-1.0001f), noise(-1.0f));
OIIO_CHECK_EQUAL_APPROX (noise(-0.9999f), noise(-1.0f));
Strutil::printf ("noise around -1: %g %g %g\n",
noise(-0.9999f), noise(-1.0f), noise(-1.0001f));
#endif
if (make_images) {
MAKE_IMAGE (noise);
}
// Time trials
benchmark1 ("snoise(f) ", snoise<float>, 0.5f);
benchmark2 ("snoise(f,f) ", snoise<float,float>, 0.5f, 0.5f);
benchmark1 ("snoise(v) ", snoise<const Vec3&>, Vec3(0,0,0));
benchmark2 ("snoise(v,f) ", snoise<const Vec3&,float>, Vec3(0,0,0), 0.5f);
Benchmarker bench;
float fval = 0.5f; clobber (fval);
Vec3 vval (0,0,0); clobber (vval);
bench (" snoise(f)", [&](){ DoNotOptimize (snoise<float>(fval)); });
bench (" snoise(f,f)", [&](){ DoNotOptimize (snoise<float,float>(fval, fval)); });
bench (" snoise(v)", [&](){ DoNotOptimize (snoise<const Vec3&>(vval)); });
bench (" snoise(v,f)", [&](){ DoNotOptimize (snoise<const Vec3&,float>(vval, fval)); });
benchmark1 ("vsnoise(f) ", vsnoise<float>, 0.5f);
benchmark2 ("vsnoise(f,f) ", vsnoise<float,float>, 0.5f, 0.5f);
benchmark1 ("vsnoise(v) ", vsnoise<const Vec3&>, Vec3(0,0,0));
benchmark2 ("vsnoise(v,f) ", vsnoise<const Vec3&,float>, Vec3(0,0,0), 0.5f);
bench (" vsnoise(f)", [&](){ DoNotOptimize (vsnoise<float>(fval)); });
bench (" vsnoise(f,f)", [&](){ DoNotOptimize (vsnoise<float,float>(fval, fval)); });
bench (" vsnoise(v)", [&](){ DoNotOptimize (vsnoise<const Vec3&>(vval)); });
bench (" vsnoise(v,f)", [&](){ DoNotOptimize (vsnoise<const Vec3&,float>(vval, fval)); });
}
@@ -287,20 +262,35 @@ test_cell ()
OIIO_CHECK_EQUAL_THRESH (vs4, vresults_4d[i], eps);
}
#if OPENIMAGEIO_VERSION >= 10904
// Make sure the right thing happens at integer cell boundaries
OIIO_CHECK_EQUAL (cellnoise( 1.0001f), cellnoise( 1.0f));
OIIO_CHECK_NE (cellnoise( 0.9999f), cellnoise( 1.0f));
OIIO_CHECK_EQUAL (cellnoise( 0.9999f), cellnoise( 0.0f));
OIIO_CHECK_EQUAL (cellnoise( 0.0001f), cellnoise( 0.0f));
OIIO_CHECK_NE (cellnoise(-0.0001f), cellnoise( 0.0f));
OIIO_CHECK_EQUAL (cellnoise(-0.0001f), cellnoise(-1.0f));
OIIO_CHECK_EQUAL (cellnoise(-0.9999f), cellnoise(-1.0f));
OIIO_CHECK_EQUAL (cellnoise(-1.0001f), cellnoise(-2.0f));
#endif
if (make_images) {
MAKE_IMAGE (cellnoise);
}
// Time trials
benchmark1 ("cellnoise(f) ", cellnoise<float>, 0.5f);
benchmark2 ("cellnoise(f,f) ", cellnoise<float,float>, 0.5f, 0.5f);
benchmark1 ("cellnoise(v) ", cellnoise<const Vec3&>, Vec3(0,0,0));
benchmark2 ("cellnoise(v,f) ", cellnoise<const Vec3&,float>, Vec3(0,0,0), 0.5f);
Benchmarker bench;
float fval = 0.5f; clobber (fval);
Vec3 vval (0,0,0); clobber (vval);
bench (" cellnoise(f)", [&](){ DoNotOptimize (cellnoise<float>(fval)); });
bench (" cellnoise(f,f)", [&](){ DoNotOptimize (cellnoise<float,float>(fval, fval)); });
bench (" cellnoise(v)", [&](){ DoNotOptimize (cellnoise<const Vec3&>(vval)); });
bench (" cellnoise(v,f)", [&](){ DoNotOptimize (cellnoise<const Vec3&,float>(vval, fval)); });
benchmark1 ("vcellnoise(f) ", vcellnoise<float>, 0.5f);
benchmark2 ("vcellnoise(f,f)", vcellnoise<float,float>, 0.5f, 0.5f);
benchmark1 ("vcellnoise(v) ", vcellnoise<const Vec3&>, Vec3(0,0,0));
benchmark2 ("vcellnoise(v,f)", vcellnoise<const Vec3&,float>, Vec3(0,0,0), 0.5f);
bench (" vcellnoise(f)", [&](){ DoNotOptimize (vcellnoise<float>(fval)); });
bench (" vcellnoise(f,f)", [&](){ DoNotOptimize (vcellnoise<float,float>(fval, fval)); });
bench (" vcellnoise(v)", [&](){ DoNotOptimize (vcellnoise<const Vec3&>(vval)); });
bench (" vcellnoise(v,f)", [&](){ DoNotOptimize (vcellnoise<const Vec3&,float>(vval, fval)); });
}
@@ -360,20 +350,34 @@ test_hash ()
OIIO_CHECK_EQUAL_THRESH (vs4, vresults_4d[i], eps);
}
#if OPENIMAGEIO_VERSION >= 10904
// Make sure the right thing happens at integer cell boundaries.
// hashnoise should be discontinuous everywhere!
OIIO_CHECK_NE (hashnoise( 0.9999f), hashnoise( 1.0f));
OIIO_CHECK_NE (hashnoise( 1.0001f), hashnoise( 1.0f));
OIIO_CHECK_NE (hashnoise(-0.0001f), hashnoise( 0.0f));
OIIO_CHECK_NE (hashnoise( 0.0001f), hashnoise( 0.0f));
OIIO_CHECK_NE (hashnoise(-1.0001f), hashnoise(-1.0f));
OIIO_CHECK_NE (hashnoise(-0.9999f), hashnoise(-1.0f));
#endif
if (make_images) {
MAKE_IMAGE (hashnoise);
}
// Time trials
benchmark1 ("hashnoise(f) ", hashnoise<float>, 0.5f);
benchmark2 ("hashnoise(f,f) ", hashnoise<float,float>, 0.5f, 0.5f);
benchmark1 ("hashnoise(v) ", hashnoise<const Vec3&>, Vec3(0,0,0));
benchmark2 ("hashnoise(v,f) ", hashnoise<const Vec3&,float>, Vec3(0,0,0), 0.5f);
Benchmarker bench;
float fval = 0.5f; clobber (fval);
Vec3 vval (0,0,0); clobber (vval);
bench (" hashnoise(f)", [&](){ DoNotOptimize (hashnoise<float>(fval)); });
bench (" hashnoise(f,f)", [&](){ DoNotOptimize (hashnoise<float,float>(fval, fval)); });
bench (" hashnoise(v)", [&](){ DoNotOptimize (hashnoise<const Vec3&>(vval)); });
bench (" hashnoise(v,f)", [&](){ DoNotOptimize (hashnoise<const Vec3&,float>(vval, fval)); });
benchmark1 ("vhashnoise(f) ", vhashnoise<float>, 0.5f);
benchmark2 ("vhashnoise(f,f)", vhashnoise<float,float>, 0.5f, 0.5f);
benchmark1 ("vhashnoise(v) ", vhashnoise<const Vec3&>, Vec3(0,0,0));
benchmark2 ("vhashnoise(v,f)", vhashnoise<const Vec3&,float>, Vec3(0,0,0), 0.5f);
bench (" vhashnoise(f)", [&](){ DoNotOptimize (vhashnoise<float>(fval)); });
bench (" vhashnoise(f,f)", [&](){ DoNotOptimize (vhashnoise<float,float>(fval, fval)); });
bench (" vhashnoise(v)", [&](){ DoNotOptimize (vhashnoise<const Vec3&>(vval)); });
bench (" vhashnoise(v,f)", [&](){ DoNotOptimize (vhashnoise<const Vec3&,float>(vval, fval)); });
}
@@ -409,6 +413,14 @@ getargs (int argc, const char *argv[])
int
main (int argc, char const *argv[])
{
#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE)
// For the sake of test time, reduce the default iterations for DEBUG,
// CI, and code coverage builds. Explicit use of --iters or --trials
// will override this, since it comes before the getargs() call.
iterations /= 10;
ntrials = 1;
#endif
getargs (argc, argv);
test_perlin ();
+25 -25
View File
@@ -80,7 +80,7 @@ OSL_NAMESPACE_ENTER
namespace pvt {
inline uint32_t
inline OSL_HOSTDEVICE uint32_t
scramble (uint32_t v0, uint32_t v1=0, uint32_t v2=0)
{
return OIIO::bjhash::bjfinal (v0, v1, v2^0xdeadbeef);
@@ -90,11 +90,11 @@ scramble (uint32_t v0, uint32_t v1=0, uint32_t v2=0)
/* Static data ---------------------- */
static float zero[] = { 0.0f, 0.0f, 0.0f, 0.0f };
static OSL_DEVICE float zero[] = { 0.0f, 0.0f, 0.0f, 0.0f };
// Gradient table for 2D. These could be programmed the Ken Perlin way with
// some clever bit-twiddling, but this is more clear, and not really slower.
static float grad2lut[8][2] = {
static OSL_DEVICE float grad2lut[8][2] = {
{ -1.0f, -1.0f }, { 1.0f, 0.0f }, { -1.0f, 0.0f }, { 1.0f, 1.0f },
{ -1.0f, 1.0f }, { 0.0f, -1.0f }, { 0.0f, 1.0f }, { 1.0f, -1.0f }
};
@@ -105,7 +105,7 @@ static float grad2lut[8][2] = {
// but these 12 (including 4 repeats to make the array length a power
// of two) work better. They are not random, they are carefully chosen
// to represent a small, isotropic set of directions.
static float grad3lut[16][3] = {
static OSL_DEVICE float grad3lut[16][3] = {
{ 1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f, 1.0f }, // 12 cube edges
{ -1.0f, 0.0f, 1.0f }, { 0.0f, -1.0f, 1.0f },
{ 1.0f, 0.0f, -1.0f }, { 0.0f, 1.0f, -1.0f },
@@ -117,7 +117,7 @@ static float grad3lut[16][3] = {
};
// Gradient directions for 4D
static float grad4lut[32][4] = {
static OSL_DEVICE float grad4lut[32][4] = {
{ 0.0f, 1.0f, 1.0f, 1.0f }, { 0.0f, 1.0f, 1.0f, -1.0f }, { 0.0f, 1.0f, -1.0f, 1.0f }, { 0.0f, 1.0f, -1.0f, -1.0f }, // 32 tesseract edges
{ 0.0f, -1.0f, 1.0f, 1.0f }, { 0.0f, -1.0f, 1.0f, -1.0f }, { 0.0f, -1.0f, -1.0f, 1.0f }, { 0.0f, -1.0f, -1.0f, -1.0f },
{ 1.0f, 0.0f, 1.0f, 1.0f }, { 1.0f, 0.0f, 1.0f, -1.0f }, { 1.0f, 0.0f, -1.0f, 1.0f }, { 1.0f, 0.0f, -1.0f, -1.0f },
@@ -131,7 +131,7 @@ static float grad4lut[32][4] = {
// A lookup table to traverse the simplex around a given point in 4D.
// Details can be found where this table is used, in the 4D noise method.
/* TODO: This should not be required, backport it from Bill's GLSL code! */
static unsigned char simplex[64][4] = {
static OSL_DEVICE unsigned char simplex[64][4] = {
{0,1,2,3},{0,1,3,2},{0,0,0,0},{0,2,3,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,2,3,0},
{0,2,1,3},{0,0,0,0},{0,3,1,2},{0,3,2,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,3,2,0},
{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},
@@ -148,7 +148,7 @@ static unsigned char simplex[64][4] = {
* and gradients-dot-residualvectors in 2D to 4D.
*/
inline float grad1 (int i, int seed)
inline OSL_HOSTDEVICE float grad1 (int i, int seed)
{
int h = scramble (i, seed);
float g = 1.0f + (h & 7); // Gradient value is one of 1.0, 2.0, ..., 8.0
@@ -157,19 +157,19 @@ inline float grad1 (int i, int seed)
return g;
}
inline const float * grad2 (int i, int j, int seed)
inline OSL_HOSTDEVICE const float * grad2 (int i, int j, int seed)
{
int h = scramble (i, j, seed);
return grad2lut[h & 7];
}
inline const float * grad3 (int i, int j, int k, int seed)
inline OSL_HOSTDEVICE const float * grad3 (int i, int j, int k, int seed)
{
int h = scramble (i, j, scramble (k, seed));
return grad3lut[h & 15];
}
inline const float * grad4 (int i, int j, int k, int l, int seed)
inline OSL_HOSTDEVICE const float * grad4 (int i, int j, int k, int l, int seed)
{
int h = scramble (i, j, scramble (k, l, seed));
return grad4lut[h & 31];
@@ -179,10 +179,10 @@ inline const float * grad4 (int i, int j, int k, int l, int seed)
// 1D simplex noise with derivative.
// If the last argument is not null, the analytic derivative
// is also calculated.
float
OSL_HOSTDEVICE float
simplexnoise1 (float x, int seed, float *dnoise_dx)
{
int i0 = quick_floor(x);
int i0 = OIIO::ifloor(x);
int i1 = i0 + 1;
float x0 = x - i0;
float x1 = x0 - 1.0f;
@@ -227,8 +227,8 @@ simplexnoise1 (float x, int seed, float *dnoise_dx)
// 2D simplex noise with derivatives.
// If the last two arguments are not null, the analytic derivative
// (the 2D gradient of the scalar noise field) is also calculated.
float simplexnoise2 (float x, float y, int seed,
float *dnoise_dx, float *dnoise_dy)
OSL_HOSTDEVICE float simplexnoise2 (float x, float y, int seed,
float *dnoise_dx, float *dnoise_dy)
{
// Skewing factors for 2D simplex grid:
const float F2 = 0.366025403; // = 0.5*(sqrt(3.0)-1.0)
@@ -239,8 +239,8 @@ float simplexnoise2 (float x, float y, int seed,
float s = ( x + y ) * F2; /* Hairy factor for 2D */
float xs = x + s;
float ys = y + s;
int i = quick_floor(xs);
int j = quick_floor(ys);
int i = OIIO::ifloor(xs);
int j = OIIO::ifloor(ys);
float t = (float) (i + j) * G2;
float X0 = i - t; /* Unskew the cell origin back to (x,y) space */
@@ -338,7 +338,7 @@ float simplexnoise2 (float x, float y, int seed,
// 3D simplex noise with derivatives.
// If the last tthree arguments are not null, the analytic derivative
// (the 3D gradient of the scalar noise field) is also calculated.
float
OSL_HOSTDEVICE float
simplexnoise3 (float x, float y, float z, int seed,
float *dnoise_dx, float *dnoise_dy, float *dnoise_dz)
{
@@ -354,9 +354,9 @@ simplexnoise3 (float x, float y, float z, int seed,
float xs = x+s;
float ys = y+s;
float zs = z+s;
int i = quick_floor(xs);
int j = quick_floor(ys);
int k = quick_floor(zs);
int i = OIIO::ifloor(xs);
int j = OIIO::ifloor(ys);
int k = OIIO::ifloor(zs);
float t = (float)(i+j+k)*G3;
float X0 = i-t; // Unskew the cell origin back to (x,y,z) space
@@ -524,7 +524,7 @@ simplexnoise3 (float x, float y, float z, int seed,
// 4D simplex noise with derivatives.
// If the last four arguments are not null, the analytic derivative
// (the 4D gradient of the scalar noise field) is also calculated.
float
OSL_HOSTDEVICE float
simplexnoise4 (float x, float y, float z, float w, int seed,
float *dnoise_dx, float *dnoise_dy,
float *dnoise_dz, float *dnoise_dw)
@@ -547,10 +547,10 @@ simplexnoise4 (float x, float y, float z, float w, int seed,
float ys = y + s;
float zs = z + s;
float ws = w + s;
int i = quick_floor(xs);
int j = quick_floor(ys);
int k = quick_floor(zs);
int l = quick_floor(ws);
int i = OIIO::ifloor(xs);
int j = OIIO::ifloor(ys);
int k = OIIO::ifloor(zs);
int l = OIIO::ifloor(ws);
float t = (i + j + k + l) * G4; // Factor for 4D unskewing
float X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
+8
View File
@@ -10,6 +10,14 @@ if (BUILDSTATIC)
ADD_LIBRARY ( oslquery STATIC ${liboslquery_srcs} )
else ()
ADD_LIBRARY ( oslquery SHARED ${liboslquery_srcs} )
if (VERBOSE)
message(STATUS "Setting SOVERSION to: ${SOVERSION}")
endif ()
set_target_properties( oslquery
PROPERTIES
VERSION ${OSL_VERSION_MAJOR}.${OSL_VERSION_MINOR}.${OSL_VERSION_PATCH}
SOVERSION ${SOVERSION} )
endif ()
TARGET_LINK_LIBRARIES ( oslquery ${OPENIMAGEIO_LIBRARIES} ${ILMBASE_LIBRARIES} ${Boost_LIBRARIES} )
+93
View File
@@ -267,6 +267,99 @@ OSOReaderQuery::codemarker (const char *name)
OSLQuery::Parameter::Parameter (const Parameter& src)
: name(src.name), type(src.type), isoutput(src.isoutput),
validdefault(src.validdefault), varlenarray(src.varlenarray),
isstruct(src.isstruct), isclosure(src.isclosure),
idefault(src.idefault), fdefault(src.fdefault),
sdefault(src.sdefault), spacename(src.spacename),
fields(src.fields), structname(src.structname),
metadata(src.metadata)
{
if (type.basetype == TypeDesc::INT)
data = idefault.data();
else if (type.basetype == TypeDesc::FLOAT)
data = fdefault.data();
else if (type.basetype == TypeDesc::STRING)
data = sdefault.data();
}
OSLQuery::Parameter::Parameter (Parameter&& src)
: name(src.name), type(src.type), isoutput(src.isoutput),
validdefault(src.validdefault), varlenarray(src.varlenarray),
isstruct(src.isstruct), isclosure(src.isclosure),
idefault(src.idefault), fdefault(src.fdefault),
sdefault(src.sdefault), spacename(src.spacename),
fields(src.fields), structname(src.structname),
metadata(src.metadata)
{
if (type.basetype == TypeDesc::INT)
data = idefault.data();
else if (type.basetype == TypeDesc::FLOAT)
data = fdefault.data();
else if (type.basetype == TypeDesc::STRING)
data = sdefault.data();
}
const OSLQuery::Parameter&
OSLQuery::Parameter::operator= (const Parameter& src)
{
name = src.name;
type = src.type;
isoutput = src.isoutput;
validdefault = src.validdefault;
varlenarray = src.varlenarray;
isstruct = src.isstruct;
isclosure = src.isclosure;
idefault = src.idefault;
fdefault = src.fdefault;
sdefault = src.sdefault;
spacename = src.spacename;
fields = src.fields;
structname = src.structname;
metadata = src.metadata;
if (type.basetype == TypeDesc::INT)
data = idefault.data();
else if (type.basetype == TypeDesc::FLOAT)
data = fdefault.data();
else if (type.basetype == TypeDesc::STRING)
data = sdefault.data();
return *this;
}
const OSLQuery::Parameter&
OSLQuery::Parameter::operator= (Parameter&& src)
{
name = src.name;
type = src.type;
isoutput = src.isoutput;
validdefault = src.validdefault;
varlenarray = src.varlenarray;
isstruct = src.isstruct;
isclosure = src.isclosure;
idefault = std::move(src.idefault);
fdefault = std::move(src.fdefault);
sdefault = std::move(src.sdefault);
spacename = src.spacename;
fields = src.fields;
structname = src.structname;
metadata = std::move(src.metadata);
if (type.basetype == TypeDesc::INT)
data = idefault.data();
else if (type.basetype == TypeDesc::FLOAT)
data = fdefault.data();
else if (type.basetype == TypeDesc::STRING)
data = sdefault.data();
return *this;
}
OSLQuery::OSLQuery ()
{
+8
View File
@@ -20,6 +20,14 @@ macro (add_oiio_plugin)
add_library (${_target_name} SHARED ${_plugin_UNPARSED_ARGUMENTS})
target_link_libraries (${_target_name} ${OPENIMAGEIO_LIBRARIES} ${_plugin_LINK_LIBRARIES})
set_target_properties (${_target_name} PROPERTIES PREFIX "" FOLDER "Plugins")
if (VERBOSE)
message(STATUS "Setting SOVERSION to: ${SOVERSION}")
endif ()
set_target_properties( ${_target_name}
PROPERTIES
VERSION ${OSL_VERSION_MAJOR}.${OSL_VERSION_MINOR}.${OSL_VERSION_PATCH}
SOVERSION ${SOVERSION} )
install_targets (${_target_name})
endmacro ()
+86 -17
View File
@@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <OpenImageIO/strutil.h>
#include <OpenImageIO/filesystem.h>
#include <OpenImageIO/thread.h>
#include <OpenImageIO/imagebuf.h>
#include <OpenImageIO/imagebufalgo.h>
#include <OSL/oslexec.h>
#include <OSL/oslcomp.h>
@@ -87,15 +87,9 @@ public:
OSLInput ();
virtual ~OSLInput ();
virtual const char * format_name (void) const { return "osl"; }
#if OPENIMAGEIO_VERSION >= 10600
virtual int supports (string_view feature) const {
return (feature == "procedural");
}
#else /* Remove the following when OIIO <= 1.5 is no longer needed */
virtual bool supports (const std::string& feature) const {
return (feature == "procedural");
}
#endif
virtual bool valid_file (const std::string &filename) const;
virtual bool open (const std::string &name, ImageSpec &newspec);
virtual bool open (const std::string &name, ImageSpec &newspec,
@@ -103,6 +97,7 @@ public:
virtual bool close ();
virtual int current_subimage (void) const { return m_subimage; }
virtual int current_miplevel (void) const { return m_miplevel; }
#if OIIO_PLUGIN_VERSION < 21 /* OIIO < 1.9 */
virtual bool seek_subimage (int subimage, int miplevel, ImageSpec &newspec);
virtual bool read_native_scanline (int y, int z, void *data);
virtual bool read_native_scanlines (int ybegin, int yend, int z,
@@ -110,6 +105,19 @@ public:
virtual bool read_native_tile (int x, int y, int z, void *data);
virtual bool read_native_tiles (int xbegin, int xend, int ybegin, int yend,
int zbegin, int zend, void *data);
#else
virtual bool seek_subimage (int subimage, int miplevel);
virtual bool read_native_scanline (int subimage, int miplevel,
int y, int z, void *data);
virtual bool read_native_scanlines (int subimage, int miplevel,
int ybegin, int yend, int z,
void *data);
virtual bool read_native_tile (int subimage, int miplevel,
int x, int y, int z, void *data);
virtual bool read_native_tiles (int subimage, int miplevel,
int xbegin, int xend, int ybegin, int yend,
int zbegin, int zend, void *data);
#endif
private:
std::string m_filename; ///< Stash the filename
ShaderGroupRef m_group;
@@ -134,6 +142,8 @@ OIIO_PLUGIN_EXPORTS_BEGIN
OIIO_EXPORT ImageInput *osl_input_imageio_create () { return new OSLInput; }
OIIO_EXPORT void osl_input_imageio_delete (ImageInput *p) { delete p; }
OIIO_EXPORT int osl_imageio_version = OIIO_PLUGIN_VERSION;
OIIO_EXPORT const char * osl_input_extensions[] = {
@@ -227,7 +237,7 @@ static ErrorRecorder errhandler;
static void
setup_shadingsys ()
{
lock_guard lock (shading_mutex);
OIIO::lock_guard lock (shading_mutex);
if (! shadingsys) {
renderer = new OIIO_RendererServices (TextureSystem::create(true));
shadingsys = new ShadingSystem (renderer, NULL, &errhandler);
@@ -490,14 +500,14 @@ OSLInput::open (const std::string &name, ImageSpec &newspec,
}
// std::cout << "Processing group specification:\n---\n"
// << groupspec << "\n---\n";
lock_guard lock (shading_mutex);
OIIO::lock_guard lock (shading_mutex);
m_group = shadingsys->ShaderGroupBegin ("", "surface", groupspec);
if (! m_group)
return false; // Failed
shadingsys->ShaderGroupEnd ();
}
if (Strutil::ends_with (shadername, ".oso")) { // Compiled shader
lock_guard lock (shading_mutex);
OIIO::lock_guard lock (shading_mutex);
shadername.remove_suffix (4);
m_group = shadingsys->ShaderGroupBegin ();
for (size_t p = 0, np = m_topspec.extra_attribs.size(); p < np; ++p) {
@@ -515,7 +525,7 @@ OSLInput::open (const std::string &name, ImageSpec &newspec,
if (Strutil::ends_with (shadername, ".osl")) { // shader source
}
if (Strutil::ends_with (shadername, ".oslbody")) { // shader source
lock_guard lock (shading_mutex);
OIIO::lock_guard lock (shading_mutex);
shadername.remove_suffix (8);
static int exprcount = 0;
std::string exprname = OIIO::Strutil::format("expr_%d", exprcount++);
@@ -554,7 +564,16 @@ OSLInput::open (const std::string &name, ImageSpec &newspec,
TypeDesc(TypeDesc::STRING,m_outputs.size()),
&m_outputs[0]);
#if OIIO_PLUGIN_VERSION < 21
return ok && seek_subimage (0, 0, newspec);
#else
ok &= seek_subimage (0, 0);
if (ok)
newspec = spec();
else
close ();
return ok;
#endif
}
@@ -569,10 +588,16 @@ OSLInput::close ()
bool
OSLInput::seek_subimage (int subimage, int miplevel, ImageSpec &newspec)
OSLInput::seek_subimage (int subimage, int miplevel
#if OIIO_PLUGIN_VERSION < 21
, ImageSpec &newspec
#endif
)
{
if (subimage == current_subimage() && miplevel == current_miplevel()) {
#if OIIO_PLUGIN_VERSION < 21
newspec = spec();
#endif
return true;
}
@@ -593,15 +618,27 @@ OSLInput::seek_subimage (int subimage, int miplevel, ImageSpec &newspec)
m_spec.full_height = m_spec.height;
m_spec.full_depth = m_spec.depth;
}
#if OIIO_PLUGIN_VERSION < 21
newspec = spec();
#endif
return true;
}
bool
OSLInput::read_native_scanlines (int ybegin, int yend, int z, void *data)
OSLInput::read_native_scanlines (
#if OIIO_PLUGIN_VERSION >= 21
int subimage, int miplevel,
#endif
int ybegin, int yend, int z, void *data)
{
#if OIIO_PLUGIN_VERSION >= 21
lock_guard lock (m_mutex);
if (! seek_subimage (subimage, miplevel))
return false;
#endif
// Create an ImageBuf wrapper of the user's data
ImageSpec spec = m_spec; // Make a spec that describes just this scanline
spec.y = ybegin;
@@ -622,17 +659,35 @@ OSLInput::read_native_scanlines (int ybegin, int yend, int z, void *data)
bool
OSLInput::read_native_scanline (int y, int z, void *data)
OSLInput::read_native_scanline (
#if OIIO_PLUGIN_VERSION >= 21
int subimage, int miplevel,
#endif
int y, int z, void *data)
{
#if OIIO_PLUGIN_VERSION >= 21
return read_native_scanlines (subimage, miplevel, y, y+1, z, data);
#else
return read_native_scanlines (y, y+1, z, data);
#endif
}
bool
OSLInput::read_native_tiles (int xbegin, int xend, int ybegin, int yend,
OSLInput::read_native_tiles (
#if OIIO_PLUGIN_VERSION >= 21
int subimage, int miplevel,
#endif
int xbegin, int xend, int ybegin, int yend,
int zbegin, int zend, void *data)
{
#if OIIO_PLUGIN_VERSION >= 21
lock_guard lock (m_mutex);
if (! seek_subimage (subimage, miplevel))
return false;
#endif
// Create an ImageBuf wrapper of the user's data
ImageSpec spec = m_spec; // Make a spec that describes just this scanline
spec.x = xbegin;
@@ -655,10 +710,24 @@ OSLInput::read_native_tiles (int xbegin, int xend, int ybegin, int yend,
bool
OSLInput::read_native_tile (int x, int y, int z, void *data)
OSLInput::read_native_tile (
#if OIIO_PLUGIN_VERSION >= 21
int subimage, int miplevel,
#endif
int x, int y, int z, void *data)
{
#if OIIO_PLUGIN_VERSION >= 21
lock_guard lock (m_mutex);
if (! seek_subimage (subimage, miplevel))
return false;
#endif
return
read_native_tiles (x, std::min (x+m_spec.tile_width, m_spec.x+m_spec.width),
read_native_tiles (
#if OIIO_PLUGIN_VERSION >= 21
subimage, miplevel,
#endif
x, std::min (x+m_spec.tile_width, m_spec.x+m_spec.width),
y, std::min (y+m_spec.tile_height, m_spec.y+m_spec.height),
z, std::min (z+m_spec.tile_depth, m_spec.z+m_spec.depth),
data);
+54 -13
View File
@@ -61,6 +61,8 @@ usage ()
"\t-O0, -O1, -O2 Set optimization level (default=1)\n"
"\t-d Debug mode\n"
"\t-E Only preprocess the input and output to stdout\n"
"\t-Werror Treat all warnings as errors\n"
"\t-buffer (debugging) Force compile from buffer\n"
;
}
@@ -108,7 +110,6 @@ static OSLC_ErrorHandler default_oslc_error_handler;
int
main (int argc, const char *argv[])
{
@@ -118,13 +119,17 @@ main (int argc, const char *argv[])
OIIO::Filesystem::convert_native_arguments (argc, (const char **)argv);
std::vector<std::string> args;
bool quiet = false;
if (argc <= 1) {
usage ();
return EXIT_SUCCESS;
}
std::vector<std::string> args;
bool quiet = false;
bool compile_from_buffer = false;
std::string shader_path;
// Parse arguments from command line
for (int a = 1; a < argc; ++a) {
if (! strcmp (argv[a], "--help") | ! strcmp (argv[a], "-h")) {
usage ();
@@ -135,12 +140,15 @@ main (int argc, const char *argv[])
! strcmp (argv[a], "-d") ||
! strcmp (argv[a], "-E") ||
! strcmp (argv[a], "-O") || ! strcmp (argv[a], "-O0") ||
! strcmp (argv[a], "-O1") || ! strcmp (argv[a], "-O2")) {
! strcmp (argv[a], "-O1") || ! strcmp (argv[a], "-O2") ||
! strcmp (argv[a], "-Werror")
) {
// Valid command-line argument
args.emplace_back(argv[a]);
quiet |= (strcmp (argv[a], "-q") == 0);
}
else if (! strcmp (argv[a], "-o") && a < argc-1) {
// Output filepath
args.emplace_back(argv[a]);
++a;
args.emplace_back(argv[a]);
@@ -149,18 +157,51 @@ main (int argc, const char *argv[])
(argv[a][1] == 'D' || argv[a][1] == 'U' || argv[a][1] == 'I')) {
args.emplace_back(argv[a]);
}
else if (!strcmp(argv[a], "-buffer")) {
compile_from_buffer = true;
}
else {
OSLCompiler compiler (&default_oslc_error_handler);
bool ok = compiler.compile (argv[a], args);
if (ok) {
if (!quiet)
std::cout << "Compiled " << argv[a] << " -> "
<< compiler.output_filename() << "\n";
} else {
std::cout << "FAILED " << argv[a] << "\n";
return EXIT_FAILURE;
// Shader to compile
shader_path = argv[a];
}
}
if (shader_path.empty ()) {
std::cout << "ERROR: Missing shader path" << "\n\n";
usage ();
return EXIT_FAILURE;
}
OSLCompiler compiler (&default_oslc_error_handler);
bool ok = true;
if (compile_from_buffer) {
// Force a compile-from-buffer for debugging purposes
std::string sourcecode;
ok = OIIO::Filesystem::read_text_file (shader_path, sourcecode);
std::string osobuffer;
if (ok)
ok = compiler.compile_buffer (sourcecode, osobuffer, args, "",
shader_path);
if (ok) {
std::ofstream file;
OIIO::Filesystem::open (file, compiler.output_filename());
if (file.good()) {
file << osobuffer;
file.close ();
}
}
} else {
// Ordinary compile from file
ok = compiler.compile (shader_path, args);
}
if (ok) {
if (!quiet)
std::cout << "Compiled " << shader_path << " -> " << compiler.output_filename() << "\n";
}
else {
std::cout << "FAILED " << shader_path << "\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
+20 -1
View File
@@ -36,7 +36,17 @@ and was distributed under BSD licensing terms identical to the
Sony Pictures Imageworks terms, above.
*/
/// <doc... oslinfo_source>
///
/// Example program using OSLQuery
/// ==============================
///
/// This is the full text of `oslinfo`, a command-line utility that
/// for any shader, will print out its parameters (name, type, default
/// values, and metadata).
///
/// ~~~~
/// <script type="preformatted">
#include <iostream>
#include <string>
#include <cstring>
@@ -58,6 +68,7 @@ static std::string oneparam;
// Print the default values for a paarameter built out of integers.
static void
print_default_string_vals (const OSLQuery::Parameter *p, bool verbose)
{
@@ -78,6 +89,8 @@ print_default_string_vals (const OSLQuery::Parameter *p, bool verbose)
// Print the default values for a paarameter built out of floats (including
// color, point, etc., or arrays thereof).
static void
print_default_int_vals (const OSLQuery::Parameter *p, bool verbose)
{
@@ -102,6 +115,7 @@ print_default_int_vals (const OSLQuery::Parameter *p, bool verbose)
// Print the default values for a paarameter built out of strings.
static void
print_default_float_vals (const OSLQuery::Parameter *p, bool verbose)
{
@@ -128,6 +142,7 @@ print_default_float_vals (const OSLQuery::Parameter *p, bool verbose)
// Print all the metadata for a parameter.
static void
print_metadata (const OSLQuery::Parameter &m)
{
@@ -264,3 +279,7 @@ main (int argc, char *argv[])
}
return EXIT_SUCCESS;
}
/// </script>
/// ~~~~

Some files were not shown because too many files have changed in this diff Show More