Compare commits

..
142 Commits
Author SHA1 Message Date
Larry Gritz 0be867f7bf Stage release v1.12.13.0
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-07-01 15:34:49 -07:00
Larry Gritz 362b01ecdd ci: switch oiio obsolete branch names to immutable tags
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-06-20 10:54:22 -07:00
Larry Gritz 657dab9da0 fix: Avoid deprecated OSLQuery ctr in test example (#1699)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-06-15 17:11:26 -07:00
Larry Gritz 26ad18688d ci: Add VFX Platform 2023 tests using new ASWF containers (#1696)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-06-14 15:06:36 -07:00
Larry Gritz a5857c5525 docs: Amend the filmography (#1695)
docs: Update the filmography

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-06-14 15:06:05 -07:00
Mitch Prater e2a3153667 docs: Fixed booboos from the previous README commit. (#1694)
Fixed booboos from the previous commit.
2023-06-14 15:05:49 -07:00
Mitch Prater 34fa5c3755 docs: README.md: added filmography and Siggraph OSL course info. (#1692)
Updated README.md to include LAIKA films and added Siggraph OSL course info to Documentation.
2023-06-14 15:05:38 -07:00
Larry Gritz 67a3c0b93c build: Changes to support fmt 10.0 (#1691)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-06-01 18:33:26 -07:00
Larry Gritz 60dcec97e7 cleanup: switch deprecated oiio simd names to modern (#1679)
Oops, I noticed that OSL was still using deprecated OIIO::simd type
aliases (float4, int4, bool4) instead of the modern vfloat4, vint4,
vbool4.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-06-01 09:41:41 -07:00
Larry Gritz cf47571daa ci: Fix package name for icc (#1690)
The Intel yum repo renamed this package a couple weeks ago, and it
broke our CI. Update to the new name.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-06-01 07:34:46 -07:00
Larry Gritz c9672c8a0d admin: Fix incorrect links in CONTRIBUTING (#1688)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-06-01 07:34:26 -07:00
AidanWelch e8fce16d36 Docs: Improve documentation of trace function (#1671)
Improve the documentation of optional parameters of trace to more accurately describe behavior.

Signed-off-by: Aidan Welch <aidan@freedwave.com>
2023-05-02 18:33:35 -07:00
Declan Russell 76f187e4d0 Fix constant float values being converted to ints (#1674)
This issue was caused by 8c52d48 . The problem is that the constant float values are being turned into ints. The PR restores the previous behavior and preserves the float format.

Note from LG explaining:

When outputting the oso and using fmt library to write the value, {} (equivalent to {:g}) prints the "simplest" text representation that, when re-parsed as a float, will give you the SAME binary float value. So the "true" value of -9.99999996e+11 is printed as -1000000000000, which when reparsed will give you the closest float to that, which is the original value. (Remember that the value of -1e12 is not exactly representable as a float.)

But if both will parse to the same float, why does the shader print -2147483648.000000 instead of -999999995904.000000? That's the interesting part.

The answer, and the real core of the problem, is that when we parse the oso file it sees -1000000000000 and thinks it's an int, lexically. Now, once it gets to figuring out what to do with that, if the initial value of a float parameter looks like an int, it's still no problem, it will convert the int to the equivalent float.

Except that in this case, because the text that looked lexically like an int is out of range for a 32 bit int, it gets INT_MIN, so by the time it's converted back to float, it's -2147483648.000000

Your fix works (at least in this instance) because it forces the value to print in a way that lexically can only be a float and not an int.

Signed-off-by: Declan Russell <declan.russell@autodesk.com>
2023-05-02 18:32:34 -07:00
Declan Russell 7678df2971 build: Fix builds when USE_PYTHON=OFF (#1675)
This issue was caused by 5efe15a. Essentially, we now use Python_EXECUTABLE to execute the serialize-bc.py script. Therefore, we have to run find_package(python) so that the Python_EXECUTABLE variable gets setup.

Signed-off-by: Declan Russell <declan.russell@autodesk.com>
2023-05-02 18:32:11 -07:00
Larry Gritz 9ffb5fb2a3 Bump version after release
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-05-01 11:11:40 -07:00
Larry Gritz f61edf2fdf Stage release v1.12.12.0
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-05-01 09:35:32 -07:00
Alejandro Conty b2190faa27 Fix userdata binding corner case (#1673)
This includes two fixes:

 1) When registering symbols that need user data, sort the entries in
 the set so the layer number is ignored. A needed udata iteam shouldn't
 depend on the layer and separating them makes find_userdata_index()
 sometimes find an index with different derivs status.

 2) osl_bind_interpolated_param() is memcpy'ing derivs that might not
 be there, yielding corrupted derivs and possibly a crash.

Signed-off-by: Alejandro Conty <aconty@imageworks.com>
2023-04-24 22:06:52 -07:00
Curtis Black 35aa264dc8 Add type information for needed attributes. (#1650)
We can currently query which attribute names and scopes are requested in a shader. This PR extends that idea to also allow querying the attribute types. This now more closely matches the equivalent available queries for user data.

For example, this shader:

```
shader Shader
{
  color c;
  getattribute("user_color", c);
  
  string s;
  getattribute("user_string", s);
}
```

allows us to do this:

```
int nattr = 0;
if (shadingSys->getattribute(shaderRef.get(), "num_attributes_needed", nattr) && nattr)
{
  // this already works
  OIIO::ustring* names = nullptr;
  shadingSys->getattribute(shaderRef.get(), "attributes_needed", OSL::TypeDesc::PTR, &names);
  
  // this is the added feature
  OIIO::TypeDesc* types = nullptr;
  shadingSys->getattribute(shaderRef.get(), "attribute_types", OSL::TypeDesc::PTR, &types);
  
  // nattr: 2
  // names: ["user_color", "user_string"]
  // types: [OIIO::TypeColor, OIIO::TypeString]
}
```

The motivation behind this feature is to perform additional type validation at material compile time when determining what primvars can be provided to the shader.

One side-effect of this change to be aware of is that, as mentioned in the code comments, if the same name is requested multiple times with different types, it will now be reported multiple times. Hopefully this is not too much of an issue as the same behaviour also occurs when an attribute is requested in multiple scopes, or when user data is requested with multiple types.

Signed-off-by: Curtis Black <curtis.w.black@gmail.com>
2023-04-10 18:51:28 -07:00
Larry Gritz 5c1617fec2 Bump version after release
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-04-05 14:14:58 -07:00
Larry Gritz f1c2299ff7 Stage for release of 1.12.11.0
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-04-05 14:12:18 -07:00
Larry Gritz c7aee41a1c Build: verify that OSL can build with clang16 (#1664)
But note: OSL does not yet work with LLVM 16.

Because homebrew recently upgraded its default llvm to 16.0, there may
be users for whom builds now break. The solution is:

    brew install llvm@14
    cmake ... -DLLVM_ROOT=/usr/local/opt/llvm@14

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-04-05 10:32:00 -07:00
Larry Gritz 79ab666246 build: proper warnings about LLVM 16 (#1658)
LLVM 16 was just released. I'm pretty sure we won't build properly
against it because of the phase-out of typed pointers in LLVM IR, so
warn prominently so that anybody building against it who has problems
will know why.

Also, LLVM itself has bumped their toolchain requirements with the
release of 16. Technically, I'm not sure if that extends to projects
using the LLVM APIs, but warn anyway and hope for the best. If it
fails, at least the warning will supply an explanation.

At a later time, we'll need to upgrade the code on our side to have the
option of using opaque pointers so we can run with LLVM 16+.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-04-02 17:33:38 -07:00
Larry Gritz c8b59032fb ci: Bump 'latest dependencies' tests to OpenEXR 3.1.7 (#1663)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-04-02 17:31:12 -07:00
Larry Gritz 0a9070cb62 Build: Fix cuda compilation flags for LLVM 15 (#1659)
For LLVM 15+, we need to disable opaque pointers. We did this for
regular bitcode generation in llvm_macros.cmake, but neglected to make
the corresponding change for copmiling to ptx in cuda_macros.cmake.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-04-02 17:30:36 -07:00
Larry Gritz 80dee64963 Qt6 compatibility (#1655)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-03-18 10:25:13 -07:00
Larry Gritz 901bea3aac Be more careful about paths to look for llvm (#1656)
In particular, `${LLVM_ROOT}/bin` will end up being (incorrectly!)
`/bin` if LLVM_ROOT is empty. That is bad if some other llvm-config
happens to be in /bin.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-03-18 10:25:00 -07:00
Larry Gritz b7a1a87dc7 ci: update runners (#1651)
* Stop using the deprecated, soon to be removed, ubuntu-18.04 runners
  and switch to 20.04.
* Bump the "latest" test openexr to 3.1.6
* Update INSTALL.md to document some things we're already testing and
  are known to work.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-03-15 22:57:57 -07:00
Larry Gritz 0c60a1a170 Fix missing // clang-format on in oslc.c (#1652)
We had turned it off in one function to preserve formatting, but
failed to turn it on at the end of the function. This led to several
small functions not being clang-formatted, now fixed.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-03-15 22:57:05 -07:00
Larry Gritz 98cc66a2e2 Bump version after release
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-03-02 10:28:51 -08:00
Larry Gritz 5592be9f11 CHANGES and stage release for 1.12.10.0
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-03-01 10:28:54 -08:00
Larry Gritz 517d10934f Update ref images from 1649
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-03-01 01:07:09 -08:00
Christopher Kulla 8ac55309ab testrender: Don't use the cached background map on the first bounce (#1649)
* testrender: Don't use the cached background map on the first bounce (camera ray)

* testrender: Change the default resolution of the background so that importance sampling is enabled by default

Signed-off-by: Chris Kulla <ckulla@gmail.com>
2023-03-01 01:07:09 -08:00
Larry Gritz c882e823c1 fix: add missing fmod variants (#1643)
Apparently some varieties of fmod(triple,float) -- which were not
documented in the spec but were intended to work and did allow that
combination in oslc -- were not fully implemented in the runtime.

* Add all these tests to the arithmetic-reg test, to fully test all
  possible argument type and unif/vary/const combinations once and for
  all for fmod. Also add some more rudimentary testing to miscmath.

* Implement the missing bits and/or avoid the code paths that rely
  on the unimplemented parts.

The implementation of fmod for funny -- both for batch and non-batch,
it's got one code path that just directly generates code and doesn't
need any functional implementation in llvm_ops at all, and a second
code path that uses the functional implementations to work around
(different, in each case!) what appears to be bugs or limitations in
long-ago LLVM versions we don't need any more.  I'm trying to assess
whether those are still needed at all in the oldest versions of LLVM
we are using, and if not, I may amend even more simplification to this
whole thing.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-02-28 16:38:26 -08:00
Larry Gritz a5777fddc5 Set up ray types for testrender (#1648)
Try to set ray types correctly for rays -- a little naive now, only
using "camera", "shadow", and "diffuse" for all rays (leave
distinguishing between reflection, refraction, diffuse, glossy for
another day, and currently testrender doesn't support subsurface or
displacement, but maybe someday).

Also, for testshade, improve efficency -- don't decode raytype on
every point.  For each individual shade, testshade was converting the
name of the raytype from a string to a ustring, then decoding to a
bitfield. Pull it all out of the loops by computing the bitfield once.

Adjust glass shaders to not change behavior based on raytype:
The code path that was supposed to suppress noisy caustic rays never
worked properly before because we never set the ray type in
testrender. Now that testrender sets it -- but does not distinguish
between the different types of secondary rays -- the code path is
active, but incorrect, and causes tests to fail. Just remove the
offending clause for now and return to the old behavior of the shader
(no attempt to eliminate caustic rays). Later, we should revamp the
glass shader entirely by switching to the newer MaterialX-inspired
closures.

Note: when you specify a resolution in the Background command in our 
scene xml, it will  run the shader out of any ray context at all (therefore
having no raytype) in order to populate an environment map that will be
used as needed. If you omit the resolution, no importance sampling is
used at all, so it's much noisier. I think the right approach is to do both --
populate the map for importance sampling, but run the shader on the rays
themselves to get higher quality visible results.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-02-28 16:38:16 -08:00
Larry Gritz c14bcd2785 Fix mismatched strides when calling OCIO for transformc with derivs (#1646)
We were getting an exception thrown on the OCIO side, because we were
passing 0 for the y stride (which, us humans know, should have been fine
since there was only one row, so the stride shouldn't have mattered).
Now pass the right stride even though we don't need to step from row
to row.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-02-20 13:44:54 -08:00
Larry Gritz a23c42fcc6 ci: Fix broken Mac CI (#1647)
Make sure LLVM_ROOT/bin (either as a cmake var or as an env var) end
up in the hints list when searching for llvm-config.

Without this, one of our Mac CI jobs was ending up with clang 14 and
llvm 15, and that was causing problems. The particular test was
supposed to be using 14 for both.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-02-20 13:44:44 -08:00
Larry Gritz 434f04d336 docs: Update credits
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-02-20 13:44:27 -08:00
Larry Gritz a1002c61c1 Typo in test shaders (#1644)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-02-20 13:43:36 -08:00
Chris Hellmuth 92b0135971 Expose llvm groupdata size as a shadergroup attribute (#1642)
Signed-off-by: Chris Hellmuth <chellmuth@gmail.com>
2023-02-20 13:43:13 -08:00
pellerington 3896d22a21 Changed snprintf formatting to satisfy some compilers. (#1640)
Signed-off-by: Peter Ellerington <elleringtonp@gmail.com>
2023-02-20 13:42:35 -08:00
Larry Gritz 500381cc64 Bump version after release
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-01-30 14:23:01 -08:00
Larry Gritz b2b5e5eaba CHANGES and stage for v1.12.9.0
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-01-30 14:22:07 -08:00
Declan Russell 8e420b4bc8 Fix some windows GPU build errors (#1638)
Signed-off-by: Declan Russell <declan.russell@autodesk.com>
2023-01-30 09:45:33 -08:00
cmstein a90ed53f88 adding relaxed type-equivalency to ReParameter() (#1639)
Signed-off-by: Clifford Stein <cstein@imageworks.com>
2023-01-27 18:59:26 -08:00
danieldresser-ie 7ee3e36dbb Fix bug with masked wide llvm_gen_closure() (#1637)
Signed-off-by: Daniel Dresser <danield@image-engine.com>
2023-01-27 18:59:10 -08:00
Larry Gritz 18d79314df Fix doc typo
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-01-27 18:58:56 -08:00
danieldresser-ie 6f9c907db8 Remove unnecessary setting of locale::global (#1636)
Signed-off-by: Daniel Dresser <danield@image-engine.com>
2023-01-12 15:16:50 -08:00
Larry Gritz b20183d13e Bump version after release
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-01-12 15:16:23 -08:00
Larry Gritz cdbc05a2b2 CHANGES and stage for v1.12.8.0
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-01-03 14:00:02 -08:00
Alex Wells b218c1853b Fix batched support for closures with array types (#1630)
Fixed batched support for closures with array types.
Enabled testsuite/userdata-custom/BATCHED (follow up to PR1620/PR1621).

Added modified version of PR1625 (Fix Issues with Derivative of getattribute) from danieldresser-ie
changing default behavior of MaskedData<DataT>::assign_all_from_scalar(const void *) to zero out Dx Dy when DataT has derviatives.
Added testsuite/userdata-custom
Fixed bug in testshades handling of userdata with derivatives.

Added bool LLVM_Util::is_type_array(llvm::Type* type)
      llvm::Type* LLVM_Util::element_type_of(llvm::Type* array_type)

Fixed icx compiler warning with src/liboslexec/osogram.y
Fixed unreferenced function warning in src/testrender/shading.cpp

Signed-off-by: Alex M. Wells <alex.m.wells@intel.com>
2023-01-02 19:13:56 -08:00
danieldresser-ie a2b9334422 Fix Batched Mode Crash When Adding A Default Initialized Closure (#1624)
This is another fix I'm attempting without really understanding all this LLVM stuff.

I started by adding a simple test case that attempts to add two closure parameters, where one has not been set.  This crashes or returns random values from uninitialized memory, matching a problem I ran into while trying to get batched mode working in Gaffer.

I investigated some, and found that add_closure_closure is assuming closure pointers are stored with the width of the current batch, but build_llvm_init is creating uniform closures.  I checked with @sfriedmapixar, who confirmed that all the batched closure code is assuming wide closures, so it seems build_llvm_init is what needs fixing.

Adding a `sym.make_varying();` to build_llvm_init appears to fix the problem ... I really don't know enough about the overall structure to know if this is the right place to make this fix, or if it could have other consequences, but it's enough to get this test passing, so hopefully someone who does know the background can review it.

Signed-off-by: Daniel Dresser <danield@image-engine.com>
2023-01-02 19:13:55 -08:00
danieldresser-ie c17553af3f Add new testshade closure to allow testing all parameter types (#1621)
Signed-off-by: Daniel Dresser <danield@image-engine.com>
2023-01-02 19:13:55 -08:00
danieldresser-ie b08c484bca Fix issue with closure keyparams batched (#1619) (#1620)
When evaluating varying closure keyword parameters in batched execution,
the value of the first lane in the batch would be used for the whole
batch.

Signed-off-by: Daniel Dresser <danield@image-engine.com>
2023-01-02 19:13:55 -08:00
Larry Gritz e5f0833d51 Fix: make various STRDECL definitions consistent in constness
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-01-02 19:11:17 -08:00
Patrick Mours 6979f995d9 Remove dependency on OptiX SDK for building core OSL with OptiX support (#1627)
Signed-off-by: Patrick Mours <pmours@nvidia.com>
2023-01-02 19:10:38 -08:00
Larry Gritz a0c3665725 Temp workaround for botched aswftesting container yum (#1633)
It seems something in the latest builds of the aswftesting/ci-osl:2022
containers has changed, and explicitly running /usr/bin/yum (instead of
the broken /usr/local/bin/yum) fixes it for now. This was completely
breaking the icc & icx tests, which require yum to install the Intel
compilers.

Also, bump up to the -clang14 containers for those tests, just to
get to a more recent LLVM.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-01-02 17:50:00 -08:00
Larry Gritz b88122e7ca CI: Fix Mac CI breakage (#1629)
To save build time, we had OSL's Mac CI tests use the homebrew
installation of openimageio. But... Homebrew recently switched its
default python to 3.11, which didn't match the versions we're testing
OSL against here and broke the python bindings, so need to make a few
adjustments.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-01-02 17:49:44 -08:00
Larry Gritz 100490bf8d CI: Fix build break by adjusting fmt version (#1631)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2023-01-02 11:48:46 -08:00
Larry Gritz 7130058741 Bump version after release
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-12-03 12:37:54 -08:00
Larry Gritz 7394f997db Stage for v1.12.7.1
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-12-03 11:15:25 -08:00
Larry Gritz f7399cee8e CMake: Adjust how version overrides work (#1617)
Related to https://github.com/OpenImageIO/oiio/pull/3653

Kai Pastor (dg0yt) points out that the recent change I made both in
OIIO and OSL to make the version a cache variable has some unexpected
side effects that can lead to unexpeted behavior by inadvertently
retaining a version number upon recompiles if the cache itself was not
cleared, and this can happen unexpectedly even when the user isn't
trying to override the version.

This patch changes the behavior as follows:

You must use the special `-DOSL_VERSION_OVERRIDE=...` to override the
version.

  * if you do so, you are playing with fire and get what you deserve
    if you misuse it or change branches and don't remember to clear
    the cache.

If you do a normal build (without trying to override the version),

  * you will get the real version number because it IS NOT cached
  * if you switch branches, you'll always get the right version number
  * ...but switching branches without clearing the cache can still, as
    always, have other subtle behavior differences versus doing a
    truly fresh build from scratch.

So in short, it still allows a way to override the version if you
really want to, but if you are not trying to do that, you can no
longer get yourself inadvertently into unexpected trouble.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-12-03 11:12:54 -08:00
Larry Gritz 5dd94cf83d CI: No longer add the ppa:ubuntu-toolchain-r/test repository (#1618)
Lately, it has been experiencing intermittent availability problems
that causes our CI to fail while setting up dependencies.

What happens if we don't use the problematic ubuntu-toolchain-r at all?

Nothing, it seems. So eliminate it.

I think that once upon a time, it was necessary to add this repo to
get certain new packages? But maybe they are mainstream enough now
that it's not necessary to add this repo? In any case, it doesn't seem
to hurt anything, it's one less moving part that can't fail if it's
not there.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-12-02 22:22:56 -08:00
Larry Gritz 78ba7b8f0d CI: Test against OpenColorIO 2.2 (#1616)
Also fix ocio brew install on Mac

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-12-02 22:22:25 -08:00
Larry Gritz 2dd1883f95 CI: Adjust when jobs are run to cut needless CI (#1615)
Changes:
* Scorecards and analysis -- allow new to cancel running old
* Scorecard only runs on main repo, no need to run on forks
* Nightly CI only runs on main repo, no need to run on forks

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-11-14 11:55:10 -08:00
Dieter De Baets 410c04ead8 Add clangSupport as dependency to fix linker error (#1613)
Signed-off-by: Dieter De Baets <dieter.baets@unity3d.com>
2022-11-14 11:54:55 -08:00
Larry Gritz a31fba5505 Bump version after release
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-30 11:43:24 -07:00
Larry Gritz 98587dfdf8 CHANGES and stage for 1.12.7.0
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-30 11:10:36 -07:00
Larry Gritz 822518f920 Testing: run pointcloud tests when partio is found (#1611)
Wow, this has been lurking for a while. Our Findpartio.cmake tries
looking for a partio exported config, but if not found, falls back
to a simple code to find it manually.

All was fine with the fallback code, which if found would set both
"partio_FOUND" and "PARTIO_FOUND". But the config file, if found --
only for the newer partio versions -- only set partio_FOUND. And in
that circumstance, we were not seting up the pointcloud tests!

Although the partio tests were running in CI (thankfully), I was not
running them locally on my machine with a new-ish partio.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-23 18:03:23 -07:00
Damien Courtois 442b265940 fixed broken links to Isotropix products (#1598)
Signed-off-by: Damien Courtois <dcourtois@isotropix.com>
2022-10-19 15:46:24 -07:00
Larry Gritz 09bfd07da7 OSL::bitcast utility (#1610)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-19 09:15:37 -07:00
Larry Gritz 74a53ff545 Improve testing coverage (partial port of #1607)
Looking at the code coverage report and trying to get a higher
coverage amount, employing two strategies: (a) remove unused code
that is not covered because it's... unused; and (b) test things
that are used but aren't in the test run. Details follow.

Disable contents of dump_struct_data_layout when OSL_DEV is not
defined, it will never be called in any other circumstances -- it's
strictly a debugging tool, not part of the shipping library.

When OSL_USE_OPTIX is not enabled, exclude compiling contents of
ptx_compile_group.

get_alignment can also be OSL_DEV only as well as simplified

Arbitrarily pick a couple of render tests to use llvm_opt levels 12
and 13 to verify that they work correctly. (That's a couple hundred
lines of pass setup code that wouldn't otherwise be included in the
coverage analysis, nor tested in the testsuite.) This also required us
to add the --llvm_opt command to testrender, as it is in testshade.

Make the analysis run build for avx512 as well for more code coverage.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-14 00:04:11 -07:00
Dan Horák 6ae6aef389 include the immintrin.h header only when needed (#1605)
The immintrin.h header is required for the implementation of the
popcount and coutr_zero function only when the Intel compiler is used.
Move the inclusion accordingly. The current state breaks build on
platforms that don't provide the header, but provide the alternative
means (gcc/clang built-ins, etc).

Signed-off-by: Dan Horák <dan@danny.cz>
2022-10-10 15:21:17 -07:00
Larry Gritz 4a44416156 Try to enable Sonar Cloud static analysis (#1551)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-06 12:21:45 -07:00
Larry Gritz a30b4f4290 Fix LPE leak in error condition (#1594)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-06 12:21:45 -07:00
Larry Gritz f31791b23a Fix memory leaks found by static analysis in leparse.cpp (#1593)
Several places in leparse.cpp were found by static analysis to have
memory leaks -- results of calling _parse() that, in the case of
early exists in error conditions, never got deleted.

I also did some other modernization: changed NULL to nullptr, changed
some loops to more compact range-for, utilize some Strutil helpers
that will be more efficient than the alternative std::string
manipulation.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-06 12:21:45 -07:00
Larry Gritz 4a9fc9cc87 OSL_ALLOCA (#1589)
We use OIIO_ALLOCA in many places. Make an OSL version and put it
in platform.h.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-06 12:21:45 -07:00
Larry Gritz 3e6c52366b CI: Move clang-format test to main section (#1588)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-06 12:21:45 -07:00
Larry Gritz a014de80fe Make testshade --help print texturesystem options and hardware info (#1584)
This was meant to work all along, which is why this patch is so small!

But a tiny detail -- not explicitly passing info about the `--help`
argument -- made ArgParse substitute its own default, which exits
after printing the usage info. But, as I apparently meant to do all
along, if you specify it explicitly, you get to handle it, and the way
we handled it alsp printed the extra information.

Anyway, with this patch, `testshade --help` not only prints all the
testshade command options, but also it prints some information at the
end about some of the build settings of OSL, versions of key
dependencies, hardware info, and a run-down of the ShadingSystem
options. This can be helpful for debugging.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-06 12:21:45 -07:00
Larry Gritz e8bbd79b70 CI: Set up a dynamic analysis test using address and leak sanitizers (#1581)
- There are a handful of tests we disable entirely with because they
  are irrelevant or just cannot be made to be clean (and that's ok).

- Tests with sanitizers run slow, so we increase timeouts, and also
  set AA to 1 for render tests to speed them up.  We rig it so a
  non-matching output won't fail, and that's ok because every other CI
  test is checking the results; here we have no reason to believe
  results will differ from other tests, we just need to run with
  sanitizers turned on.

- In testing.cmake, we rig texture tests to disable the leak
  sanitizer, because we can't eliminate some completely benign leaks
  from the texture system, and because they are called from JITed
  code, we don't get a clean stack trace of things that happen in OIIO
  and therefore we just can't enumerate the allowed exceptions. So we
  trust that OIIO itself tests the texture system adequately and is
  able to ignore the benign "leaks."

- We already submitted PRs and merged the little fixes that were
  discovered by enabling address and leak sanitizers. This is just the
  final bit to turn it on for CI runs from here on out.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-06 12:21:45 -07:00
Larry Gritz b75ce26416 Fix memory leak in ASTvariable_declaration (#1576)
* Fix memory leak in ASTvariable_declaration

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-10-06 12:21:45 -07:00
Alex Wells c193b0753e CI: address regressions with new icx compiler (#1601)
Some explicit SIMD loops were technically illegal because each lane was not truly independent, fixed by adding "reduction" clause.  Some Mask objects had to be replaced with just "int" to allow it to be specified in the reduction clause.

icx v2022.2.0 does apppear to have some regressions for large amounts of Dual code in a couple use cases, added alternative(improved) Single Statement Assignment (SSA) version of OIIO::fast_sincos which allowed unit tests to pass.  Consider updating OIIO fmath.h to use SSA coding style (which would allow this workaround to be removed).
Another regression with transform_normals was avoiding by introducing an OSL_UNLIKELY(condition) to generate a branch vs. masked execution, this change is a general improvement and should be left in.

Avoid flex_bison produced warning in osogram.cpp "variable 'osonerrs' set but not used".

Due to a number of regressions that appear to be fixed in next revision, choose to skip icx 2022.2 and continue CI for the time being with icx 2022.1 until the next release.

Because multiple (possibly newer) versions of oneapi may be installed, use a config file to specific a specific compiler and tbb version NOTE: Individual oneapi components may independent version numbering.

For centos images, use a config file to specificy a specific oneapi compiler and tbb version

Signed-off-by: Alex M. Wells <alex.m.wells@intel.com>
2022-10-06 10:53:11 -07:00
Larry Gritz cf725983de Batched analysis: ReadEvent remove uninitialized members (#1575)
The little ReadEvent class had two members that are never set when
OSL_DEV is not defined, nor are they accessible (the accessor
functions also are disabled based on OSL_DEV). It looked to the static
analyzer like the data members were uninitialized, which they
were. Add OSL_DEV guards around the declarations of those members as
well, so they aren't even present in the struct when not needed for
this debugging mode.

Food for thought: another alternative is to keep the members but just
remove the OSL_DEV guards entirely -- just let the two int data
members be used all the time, not just for OSL_DEV. It's too small to
have any perf penalty, and it unclutters the declaration by removing
all those `#ifdef` lines.

For that matter, I also wonder if there's any real point to having
private members and accessor functions for this tiny internal-only
class, and maybe it's better to just let it be compact declaration
of a simple `struct` with three directly accessible data members.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-30 16:46:37 -07:00
Larry Gritz fc16c8dde2 Rewrite confusing loop in testshade for clarity (#1574)
In testshade, there was a "loop" that wasn't really a loop, and it
was getting flagged by static analysis as being fishy. This patch
rewrites it as an "if".

Also take the opportunity to change from stream output to OSL::print
formatted output.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-30 16:46:37 -07:00
Larry Gritz 257ca66afe Build/test: parameterize the timeout for expensive tests (#1571)
We had hard-coded longer allowable timeouts for particular testsuite
tests. But for the static analysis runs, it takes extra long and we
need a way to tell it to increase the timeouts even more, and to
exclude the longest running tests from the analysis coverage run (it's
not necessary to run those tests, they don't increase coverage enough
to justify being an hours long run).

Signed-off-by: Larry Gritz <lg@larrygritz.com>

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-30 16:46:37 -07:00
Larry Gritz fde2a3e5ee Rename compiler-generated constants non-sequentially (#1570)
In the course of our runtime optimization of shader networks, we
generate lots of new constant symbols (for example, as we optimize an
"a = b + c" into "a = newconst" if b and c can be determined to be
constants). The new constants are named with a numerical suffix doled
out in a sequental manner.

I've always thought that maybe it would be helpful for me when
debugging optimizer output if the name of the symbol also revealed the
value of the constant it held (when possible). Never did anything
about it.

Now it turns out that this has an application for JIT to PTX, where
the PTX cache can save compilation-to-PTX time if it encounters LLVM
IR that is exactly the same as it has seen before and is cache.  If
the constants are generated in a different order, it generates
non-functional, purely text differences in the code we generate, and
this means the PTX cache doesn't function as efficiently as possible.

So this change alters the compiler-generated constant naming for two
cases: int constants, and string constants. The int constants append
the value of the integer (using '_' instead of '-' for negatives), and
the string constants append the hexidecimal value of the ustring hash
for that string. In both cases it does this without using or
incrementing the `m_next_newconst` counter that it uses to
sequentially name the other types that can't easily encode the value
to generate a unique name.

It's really to help the PTX cache, but as a side benefit, it will
be slightly easier for me to make sense of the optimized code when
I need to read it with my own eyes while debugging.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-30 16:46:37 -07:00
Larry Gritz 6906daebdc Bump version after release
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-30 16:46:37 -07:00
Larry Gritz d80bbaa50a Stage for release
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-30 16:43:53 -07:00
Larry Gritz a1a77b86ab LLVM 15.0 support (#1592)
* A variety of changes to get a clean build and passing tests when
  using LLVM 15.0.

* I've noticed problems when using LLVM 15 but building with earlier
  clang, so the cmake scripts now print a warning in that case, so if
  users encounter trouble they have a hint about what to do to fix it.

* For our CI tests on Mac, force the MacOS-11 test to use llvm 14,
  and the MacOS-12 test to use llvm 15.

IMPORTANT TO-DO / CAVEATS:

1. When doing JIT at optlevel 12 or 13, I had to disable a number of
   passes that don't seem to exist anymore in LLVM 15. This is enough
   to get it working, and to be honest, I don't know if anybody uses
   these opt levels.  But we need to revisit this, because I don't
   know if there these are cases where the names of the passes merely
   changed or that new passes take their place (in which case we
   should add the new passes, not stop after merely disabling the
   deprecated ones). For that matter, optlevel modes 11, 12, 13 are
   supposed to match what clang does for -O1, -O2, -O3, and that
   changes from one release to the next, so we should probably revisit
   this list and make sure it's matching clang's current choices
   (which I assume are crafted and periodically revised by clang's
   authors).

2. LLVM 15 switches to "opaque pointers". It still supports typed
   pointers...  for now. But as you can see in the diffs, I had to
   disable a variety of deprecation warnings and take some other
   actions to put LLVM 15 in the old "opaque ptr" mode to match our
   use of LLVM <= 14. But this is only temporary, because the typed
   pointer mode is expected to be removed entirely in LLVM 16. So at
   some point in the next few months, we are going to need to support
   opaque pointers in our use of LLVM. (Also note: for a while, we're
   going to have a bunch of ugly `#if` guards or other logic to
   support both opaque pointers for users with llvm >= 16 and also
   typed pointers for users with llvm <= 14, until such time as our
   LLVM minimum is at least 15, which I expect is not a reasonable
   assumption for at least a couple years.)

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-29 10:12:44 -07:00
Larry Gritz 267c93104b Fixes to compile with clang 15 (#1586)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-29 10:12:38 -07:00
Larry Gritz d08f476b3c OSL v1.12.6.1-RC1 release candidate for 1.12
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-24 14:45:19 -07:00
Larry Gritz 7e9ddadc0f Docs: Some minor updates to CONTRIBUTIONS and INSTALL docs (#1582)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-22 14:49:37 -07:00
Mark Sisson 0cdf072c22 add .envrc to .gitignore (#1583)
direnv (https://github.com/direnv/direnv) can be used for local developer workflow enhancements.  direnv uses .envrc file for configuration.  Because .envrc is usually specific to a developer workflow, it is generally not committed.

Signed-off-by: Mark Sisson <5761292+marksisson@users.noreply.github.com>
2022-09-22 14:49:33 -07:00
Chris Hellmuth 9f033074fa Docs: Minor spec typos (#1580)
* Fix minor spec typos

Signed-off-by: Chris Hellmuth <chellmuth@gmail.com>
2022-09-19 18:33:48 -07:00
Larry Gritz 6d9db5a761 Build: Make the version number be a cmake cache variable (#1579)
Rather than specify the version in the usual project() statement,

    project (OSL VERSION 1.13.0.0 ...)

this patch decouples it

    set (OSL_VERSION "1.13.0.0" CACHE STRING "Version")
    project (OSL VERSION ${OSLVERSION} ...)

thus allowing the possibility of overriding the version number at
build confuguration time (`cmake -DOSL_VERSION=3.1.4.1`).

This should be used with extreme caution. Probably never used by most
people. I don't need to describe all the ways that things can go
sideways if you make your build of x.y.z.w actually be arbitrarily
different from the x.y.z.w that everyone else uses and that is
documented.

That said, there are two scenarios I have in mind for which this
ability is very useful:

1. Sometimes, we add or deprecate API features "in advance" by having
   an `#if` enable or disable code based on the version, essentially
   putting in place changes that can't be enabled yet because they
   would break compatibility rules, but we want to integrate the code
   now and have it become active upon reaching a particular future
   version in which that incompatibility will be allowed. The version
   number override makes it easy to test this by quickly doing a build
   "as if" we had already bumped the version number to see what will
   happen when we actually do.

2. Every once in a while we need to do an internal build that, to
   conform to version compatibility rules, needs to appear to still be
   part of a past version family. This lets individual sites play some
   games with version number overrides rather than have to create new
   branches and tags for certain one-off internal releases.

Signed-off-by: Larry Gritz <lg@larrygritz.com>

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-13 15:17:01 -07:00
Larry Gritz 6cd6849580 Bug fix: assigning init-op param its default value as instance got lost (#1578)
This is a tricky situation to describe. Consider this shader:

    shader test (float A = 0.5,
                 float B = A)
    {
        printf("A = %g, B = %g\n", A, B);
    }

By default, A is 0.5 and B gets A's value, also 0.5. If you give A a
different instance value, like 1.0, then B will also get the same
value, they'll both be 1.0.  If you give B an instance value, that
will be used for B rather than copying A's value, like this:

    $ testshade  -param B 1.0 -shader test test
    A = 0.5, B = 1

But there is a corner case bug: if we assign B an instance value of
0.0, it will incorrectly fall into a special case where it thinks it
gets a default value, only coincidentally because 0.0 is in an unused
slot for the default value (unused because it has no default -- its
default comes from "init ops", that assignment).

    $ testshade  -param B 0.0 -shader test test
    A = 0.5, B = 0.5

!!!

Reading the patch should be self-explanatory for what the bug is and
how we fix it.

Signed-off-by: Larry Gritz <lg@larrygritz.com>

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-12 17:52:03 -07:00
Larry GritzandAlex Wells db1dcc1053 Fix overrunning allocation region in debug common_ancestor_between (#1577)
Signed-off-by: Alex Wells <alex.m.wells@intel.com>
Signed-off-by: Larry Gritz <lg@larrygritz.com>
Co-authored-by: Alex Wells <alex.m.wells@intel.com>
2022-09-12 17:52:03 -07:00
Larry Gritz af15fb3b3d Docs: RELEASING.md (#1572)
I've tried to write a complete set of step-by-step instructions for
everything about how to coordinate and deploy a release. This is a
living document, we will amend over time. I'm sure there must be
things I've forgotten.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-12 17:52:03 -07:00
Larry Gritz 9e9acd1592 Bump version after beta tag
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-12 17:52:03 -07:00
Larry Gritz 60975da4e2 CHANGES
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-01 18:17:02 -07:00
Larry Gritz c25cdd4eab Bump version and designate beta
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-01 18:01:05 -07:00
Larry Gritz 01284d3af8 CHANGES
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-01 18:01:05 -07:00
Larry Gritz c0185c1482 Rebuild PDF docs
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-01 15:58:50 -07:00
Larry Gritz 93866b7c77 Deal with deprecated bit_cast function in OIIO 2.5 (#1569)
Today's branching of OIIO 2.4 and subsequent changing of its master
branch to think it's "2.5" seems to have triggered an automatic fuse
that annotates a particular function in OIIO as deprecated for version
2.5 and beyond. OSL was still calling the old version, so some
immediate changes are necessary to call the correct new name when
using a new OIIO.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-01 15:58:50 -07:00
Larry Gritz d9db605bed Make sure all clang-format changes are in .git-blame-ignore-revs (#1568)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-09-01 12:21:10 -07:00
Larry Gritz 13d2c1914f New closure docs (#1564)
* Change the languagespec to document the new MaterialX-synchronized
  closures.

* Document the old ones as "deprecated" -- still supported for 1.x but
  assumed to be on the slate for removal in OSL 2.x.

* Change stdosl.h so that the new closures, instead of being seen only
  if MATERIALX_CLOSURES is defined, to being enabled by default, but
  (for now) can be disabled if NO_MATERIALX_CLOSURES is defined.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-31 14:23:23 -07:00
Larry Gritz 61d10d6aaf CI: test against python 3.10, gcc 12, latest fmt, update INSTALL (#1565)
Mostly, updating the "latest versions" test to the current latest
versions.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-31 14:23:09 -07:00
Larry Gritz 3601a3fd1c Simplify clang-format call now that we include virtually everything (#1562)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-29 09:30:54 -07:00
Larry Gritz 2d6210a893 Sonar warning fixes and improvements (based on #1563)
* Minor changes to fix a couple more warnings given by SonarCloud
  static analysis.

* Get the code coverage enabled, it wasn't running properly.

* testrender: allow secret TESTRENDER_AA to override command line --aa

* runtest.py: allow secret OSL_TESTSUITE_SKIP_DIFF to force skipping
  the reference comparison step.

* For analysis run, set TESTRENDER_AA=1 to keep the tests from being
  prohibitively expensive, and OSL_TESTSUITE_SKIP_DIFF=1 to keep it
  from failing because the aa=1 images are different.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-29 09:30:54 -07:00
Larry Gritz 26e8da310b Fix OptiX + clang14 issue with duplicate symbols (#1561)
We had been using clang/llvm 12 and when trying out 14 I started
getting test failures with OptiX complaining about duplicate
symbols. They all seemed to be the things we declared as
OSL_CONSTANT_DATA. It looks like there's a difference in llvm 12 vs 14
in how the generated PTX marks its symbol visibility.

The solution (thanks to a clever suggestion by Alex Conty) was just to
enclose those declarations in anonymous namespaces. Works like a
charm!

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-29 09:30:54 -07:00
Larry Gritz 07b2d9fb15 Fix minor bugs and warnings uncovered by SonarCloud (#1556)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-28 23:26:22 -07:00
Larry Gritz 6c06652cfd Fixes needed to support OptiX 7.4 (#1559)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-28 23:25:14 -07:00
Larry Gritz 4ee62cd2ef clang-format: the very last piece of the puzzle (#1555)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-26 13:45:47 -07:00
Christopher Kulla 68c67633f5 Add missing cases for MaterilaX closure refraction index detection (#1557)
This allows the refraction index to be detected even if a medium closure
is not present. Additionally, the medium detection now traverses layer()
closures.

Signed-off-by: Chris Kulla <ckulla@gmail.com>
2022-08-23 00:07:48 -07:00
Larry Gritz 6f65f91b49 Testing: Try to fix testsuite/render-microfacet failures (#1558)
There seems to be just a teensy bit of nondeterminism or
platform-variance in this one test that we haven't tracked down the
source of yet, that moves some specular fireflies around. Smells like
maybe an uninitialized variable somewhere in testrender? Because it
doesn't happen on any other test and we haven't detected it in our
real renderer, we don't currently suspect that it's an actual error
in oslexec.

Big hack: Re-run failed "render" tests up to 5 additional times before
giving up.

This makes me feel dirty. But it makes tests pass for now. Eventually we
will find the embarrassing testrender bug that is responsible for the
occasionally different specular sampling noise.

Also slightly bump up the error tolerance for this test.

Also add one alternative that seems to frequently pop up.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-23 00:07:40 -07:00
Larry Gritz 475a109281 CI: For Mac, test python 3.9 for MacOS11, and 3.10 for MacOS12 (#1554)
This cleans up some recently-failing CI tests.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-23 00:07:28 -07:00
Larry Gritz 91eb43227a CHANGES
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-20 17:15:38 -07:00
Larry Gritz 8c2a10268f CHANGES and other misc docs fixups
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-20 00:22:29 -07:00
Larry Gritz ec8ec11cfd Fix typo error that prevented correct typecheck of ternary (#1552)
Didn't properly detect the disallowed use of arrays for the false
clause because we checked `t` twice.

Yay for static analysis!

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-20 00:22:29 -07:00
Larry Gritz 61bb9ac11e Fix spelling
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-20 00:22:29 -07:00
Larry Gritz bd7d138f04 Spell check comments (#1550)
Yay for "codespell"

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-04 17:31:51 -07:00
Larry Gritz 38015b6be2 Another round of clang-format (#1540)
* Another round of clang-format

* Bump the standard clang-format we use for CI from clang11 to clang14.
  This will make some minor additional changes.

* Due to a mismatched target name, we weren't actually checking the
  formatting in CI on all the files we thought we were, and therefore
  not assuring that certain code was correctly formatted. So there is
  some fixup needed, which is included here.

* And a bunch of files we didn't try to do before, either.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-04 17:05:36 -07:00
Alejandro Conty d42c5d3e1d Switch testrender to cone tracing (#1543)
The idea is to stop propagating derivs through BSDFs, which we
never did properly. Instead we trace rays with radius + spread,
which we turn into OSL derivs in SG when we hit a surface. Then
when bouncing off a surface we use the BSDF roughness to set the
spread. In addition we also:

  * Return BSDF samples/eval as a small struct Sample(). This
    avoids output parameters in the methods.
  * Stop passing a full ShaderGlobals to the BSDF methods. Pass
    a viewing direction wo instead so they could run in a simpler
    context.

Signed-off-by: Alejandro Conty <aconty@imageworks.com>
2022-08-03 23:25:09 -07:00
Larry Gritz 162b355bc8 Testing: Adjust comparison thresholds to account for platform diffs (#1549)
Also fix a CI test label -- we had a duplicate.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-02 13:10:08 -04:00
Christopher Kulla d383680521 Implement MaterialX medium closure and use it to drive the refraction closures (#1547)
This simplifies the logic around the ior which drives reflection/transmission (fresnel effect)
from the ior which drives refraction (and total internal reflection). Setting both iors equal to each other
gives the expected physical behavior.

Also tweak the bsdf constructor to support variadic arguments which simplifies a bunch of code.

Add a new test to validate the refractive version of generalized_schlick_bsdf.

Signed-off-by: Chris Kulla <ckulla@gmail.com>
2022-08-02 13:10:03 -04:00
Christopher Kulla 95ed032dcd Add furnace tests for MaterialX closures (#1542)
Implement get_albedo for the sheen closure, based on fit derived by the MaterialX team

Add optional mode to testrender to visualize the result of the get_albedo method. This can be useful for validation of the get_albedo method.

Signed-off-by: Chris Kulla <ckulla@gmail.com>
2022-08-02 13:06:27 -04:00
Larry Gritz 0c5544e4dc Increase error threshold for tests (#1546)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-08-01 10:47:51 -04:00
Christopher Kulla 54844fe68d Implement microfacet based MaterialX closures (#1541)
* Implement reflective microfacet based MaterialX closures

Add test cases for dielectric, conductor and generalized schlick closures

Signed-off-by: Chris Kulla <ckulla@gmail.com>

* Implement refraction case in microfacet closures

Signed-off-by: Chris Kulla <ckulla@gmail.com>

* Update reference images

Signed-off-by: Chris Kulla <ckulla@gmail.com>

* Relax diff threshold on render tests

Signed-off-by: Chris Kulla <ckulla@gmail.com>
2022-08-01 10:47:43 -04:00
Larry Gritz 760561d74e Label ci jobs better (#1545)
This was resulting in confusing artifact names for the Intel compiler
cases.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-07-31 19:32:28 -04:00
Larry Gritz 354eb8576c Fix error message for texture-errormsg test (#1544)
It printed the u,v coordinates where the error was first discovered.
This is not necessarily deterministic, of course!

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-07-31 19:32:22 -04:00
Adrien Herubel a725f2b97e Layer closure implementation in testrender (#1538)
* Add support for layer closure with dielectric reflections as top layers, and a test with nested layer closures

* Add support for sheen in the layer closure

Signed-off-by: Adrien Herubel <adrien.herubel@autodesk.com>
2022-07-24 14:28:57 -07:00
Adrien Herubel 29e8d0bf50 Missing documentation for the exponent parameter in the generalized_schlick_bsdf, and missing storage for the parameter (#1539)
Signed-off-by: Adrien Herubel <adrien.herubel@autodesk.com>
2022-07-24 11:31:19 -07:00
Christopher Kulla 422c0966a6 Implement MaterialX closure sheen_bsdf (#1537)
Signed-off-by: Chris Kulla <ckulla@gmail.com>
2022-07-22 18:15:28 -07:00
Christopher Kulla 9b706d30bf Implement MaterialX closure burley_diffuse_bsdf (#1536)
Signed-off-by: Chris Kulla <ckulla@gmail.com>
2022-07-22 18:15:23 -07:00
Christopher Kulla ceda8c0d23 Implement basic support for MaterialX closures in testrender (#1533)
* Extend the bsdf interface in testrender to use Color3 instead of float in preparation for MaterialX closures which are almost all tinted

  * Add stub parameters and IDs for all MaterialX closures

  * Register all MaterialX closure types

  * Implement most MaterialX closures, reusing the existing implementations for now

This commit is mainly intended to do the busy work of adding the new closures, no new BSDFs are actually implemented yet. This means that some of
the closures are handled in a very rudimentary way, ignoring some key parameters. The intent is to improve support for these over time.

Signed-off-by: Chris Kulla <ckulla@gmail.com>
2022-07-22 18:15:16 -07:00
Christopher Kulla b561a67ad1 Modernize sampler in testrender (#1534)
The sampler implementation in testrender was very close to the 2020 article from Brent Burley. This patch
catches up to best practices, including a faster owen scrambler from Nathan Vegdahl and recognizing that
the index scrambling can be achived by the same owen scrambler method (which saves a bunch of logic and runs
faster). Finally, avoid the redundant bit reversals and use compiler intrinsics when available to benefit
from hardware instructions (for ARM or GPUs). Finally the integer hash constants were updated to the latest
from the hash prospector project.

While more optimizations are certainly possible, this is a reasonable balance between quality and speed.

Update reference images for new sampler

Signed-off-by: Chris Kulla <ckulla@gmail.com>
2022-07-22 18:15:10 -07:00
Larry Gritz 4e34e8dd20 Mark DCO task as long since done (#1532)
Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-07-22 18:14:46 -07:00
Adrien Herubel 905058ee13 Fix permission error and build errors when running serialize-bc.py on Linux (#1527)
Signed-off-by: Adrien Herubel <adrien.herubel@autodesk.com>
2022-07-06 08:56:52 -07:00
Larry Gritz d3e443b766 Security policy fixes (#1529)
* Set up a SECURITY.md explaining how to confidentially report
  vulnerabilities.

* Create scorecards.yml workflow to run OSSF scorecard to check supply
  chain security issues.

* Use exact SHA's for actions versions to guard against hijacked
  actions repos that might try to substutite something else at the
  version tag we use.

* Make sure actions we use don't get write perms on our repo.

* Tried to use harden-runner action to ensure no actions on the runner
  overwrite source code or have unauthorized outgoing net connections
  during the GHA run, but currently leaving it disabled because of too
  many false positives -- it flags every dependency download as a case
  of altering source code. Which it technically is, but it doesn't
  matter for any jobs that aren't producing any artifacts that will be
  consumed or relied on by users.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-06-30 23:13:39 -07:00
Larry Gritz d860eae924 Allow naming of llvm symbols for many ops (#1530)
Most LLVM API IR calls that generate ops allow an optional name of the
llvm symbol that will hold the result of the operation. By default, it
will make one up, such as "%37", "%38", etc. Needless to say, these
are difficult to understand when reading volumes of IR dumped for
debugging purposes.

So in this patch, I'm starting to expose the ability for our own code
to pass names through our wrapper functions. I needed this for some
deep debugging.

I haven't instrumented the entire set, just trying it on for some of
the specific areas I needed to debug. But this is a useful first step.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-06-30 16:23:13 -07:00
Adrien Herubel 71a518e9a5 Remove unwanted characters causing compilation errors in the MaterialX closure definitions (#1528)
Signed-off-by: Adrien Herubel <adrien.herubel@autodesk.com>
2022-06-24 11:16:40 -07:00
Larry Gritz 2bbd6610c8 Remove confusing licensing comment (#1521)
The implementation of simplex noise we've been using is public domain,
but looks like when we pasted the license notice into our repo, there
was one stray sentence (probably left over from an earlier license
scheme Stefan Gustavson used?) that makes reference to GPL. But the
software and its repo are NOT -- it's very clear that it's public
domain: https://github.com/stegu/perlin-noise/blob/master/LICENSE.md

So remove this confusing sentence.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-06-20 11:13:23 -07:00
Larry Gritz 5bcee23e34 Branch for eventual release, call it alpha (#1522)
Aiming to declare a stable beta soon and release circa SIGGRAPH.

Primarily, this branch is to allow us to continue changing main in
ways that would be destabilizing before the release.
New things that go in main that are risk or break compatibility
will not be backported to this new branch.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
2022-06-20 11:10:51 -07:00
151 changed files with 5424 additions and 1815 deletions
+4 -16
View File
@@ -12,7 +12,7 @@ on:
# - cron: "0 0 * * 0"
push:
branches:
- main
# - master
- '*analysis*'
# Allow manual kicking off of the workflow from github.com
workflow_dispatch:
@@ -37,12 +37,10 @@ jobs:
include:
- desc: sonar gcc9/C++14 llvm13 py3.9 boost1.76 exr3.1 oiio2.3 avx2
nametag: static-analysis-sonar
os: ubuntu-20.04-8c-32g-300h
# os: ubuntu-latest
os: ubuntu-latest
vfxyear: 2022
vfxsuffix: -clang13
cxx_std: 14
openimageio_ver: master
python_ver: 3.9
pybind11_ver: v2.9.0
simd: avx2,f16c
@@ -60,7 +58,7 @@ jobs:
TESTRENDER_AA=1
OSL_TESTSUITE_SKIP_DIFF=1
CTEST_TEST_TIMEOUT=1200
OSL_CMAKE_FLAGS="-DOSL_TEST_BIG_TIMEOUT=1200 -DUSE_QT=0"
OSL_CMAKE_FLAGS="-DOSL_TEST_BIG_TIMEOUT=1200"
CTEST_EXCLUSIONS="broken|noise-reg.regress|noise-gabor-reg.regress"
runs-on: ${{ matrix.os }}
@@ -70,14 +68,11 @@ jobs:
CXX: ${{matrix.cxx_compiler}}
CC: ${{matrix.cc_compiler}}
CMAKE_CXX_STANDARD: ${{matrix.cxx_std}}
USE_SIMD: ${{matrix.simd}}
FMT_VERSION: ${{matrix.fmt_ver}}
OPENEXR_VERSION: ${{matrix.openexr_ver}}
OPENIMAGEIO_VERSION: ${{matrix.openimageio_ver}}
PYBIND11_VERSION: ${{matrix.pybind11_ver}}
PYTHON_VERSION: ${{matrix.python_ver}}
USE_BATCHED: ${{matrix.batched}}
USE_SIMD: ${{matrix.simd}}
PARALLEL: 24
# DEBUG_CI: 1
steps:
# We would like to use harden-runner, but it flags too many false
@@ -104,13 +99,6 @@ jobs:
run: |
${{matrix.setenvs}}
src/build-scripts/ci-startup.bash
- name: Remove existing OIIO
if: matrix.openimageio_ver != ''
run: |
sudo rm -rf /usr/local/include/OpenImageIO
sudo rm -rf /usr/local/lib*/cmake/OpenImageIO
sudo rm -rf /usr/local/lib*/libOpenImageIO*
sudo rm -rf /usr/local/lib*/python3.9/site-packages/OpenImageIO*
- name: Dependencies
run: |
${{matrix.depcmds}}
+52 -39
View File
@@ -20,16 +20,13 @@ on:
- '**.rst'
- '**.tex'
schedule:
# Full nightly build
# Full nightly build, for the main project repo (not for forks)
- cron: "0 6 * * *"
if: github.repository == 'AcademySoftwareFoundation/OpenShadingLanguage'
permissions: read-all
# Allow subsequent pushes to the same PR or REF to cancel any previous jobs.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
@@ -39,20 +36,20 @@ jobs:
fail-fast: false
matrix:
include:
- desc: gcc6/C++14 llvm9 py2.7 boost1.66 exr2.3 oiio2.2 sse2
- desc: gcc6/C++14 llvm9 py2.7 boost1.66 exr2.3 oiio2.3 sse2
nametag: linux-vfx2019
os: ubuntu-latest
container: aswftesting/ci-osl:2019-clang9
vfxyear: 2019
vfxsuffix: -clang9
cxx_std: 14
openimageio_ver: v2.3.17.0
openimageio_ver: v2.2.17.0
python_ver: 2.7
pybind11_ver: v2.4.2
- desc: clang9/C++14 llvm9 oiio-release boost1.66 avx2 exr2.3 py2.7
nametag: linux-clang9-llvm9
os: ubuntu-18.04
os: ubuntu-20.04
container: aswftesting/ci-osl:2019-clang9
vfxyear: 2019
vfxsuffix: -clang9
cc_compiler: clang
cxx_compiler: clang++
cxx_std: 14
@@ -63,41 +60,43 @@ jobs:
- desc: GPU Cuda10 gcc6/C++14 llvm10 py2.7 boost-1.70 exr-2.3 OIIO-master avx2
nametag: linux-optix7-2019
os: ubuntu-latest
container: aswftesting/ci-osl:2019-clang10
vfxyear: 2019
vfxsuffix: -clang10
cxx_std: 14
openimageio_ver: master
python_ver: 2.7
# pybind11_ver: v2.9.0
simd: avx2,f16c
skip_tests: 1
setenvs: export OSL_CMAKE_FLAGS="-DUSE_OPTIX=1" OPTIX_VERSION=7.0
setenvs: export OSL_CMAKE_FLAGS="-DUSE_OPTIX=1" OPTIX_VERSION=7.0
OPENIMAGEIO_CMAKE_FLAGS=-DBUILD_FMT_VERSION=8.1.1
- desc: gcc6/C++14 llvm10 py3.7 boost1.70 exr2.4 oiio2.2 sse4
nametag: linux-vfx2020
os: ubuntu-latest
container: aswftesting/ci-osl:2020
vfxyear: 2020
cxx_std: 14
openimageio_ver: v2.3.17.0
openimageio_ver: v2.2.17.0
python_ver: 3.7
pybind11_ver: v2.5.0
simd: sse4.2
setenvs: export CONAN_LLVM_VERSION=10.0.1
- desc: gcc9/C++17 llvm11 py3.7 boost1.73 exr2.5 oiio2.2 avx2 batch-b8avx2
- desc: gcc9/C++17 llvm11 py3.7 boost1.73 exr2.5 oiio2.3 avx2 batch-b8avx2
nametag: linux-vfx2021
os: ubuntu-latest
container: aswftesting/ci-osl:2021-clang11
vfxyear: 2021
vfxsuffix: -clang11
cxx_std: 17
openimageio_ver: dev-2.3
openimageio_ver: v2.2.21.0
python_ver: 3.7
pybind11_ver: v2.7.0
simd: avx2,f16c
batched: b8_AVX2_noFMA
- desc: gcc9/C++17 llvm13 py3.9 boost1.76 exr3.1 oiio2.3 avx2
- desc: gcc9/C++17 llvm13 py3.9 boost1.76 exr3.1 oiio-rel avx2
nametag: linux-vfx2022
os: ubuntu-latest
container: aswftesting/ci-osl:2022-clang13
vfxyear: 2022
vfxsuffix: -clang13
cxx_std: 17
openimageio_ver: release
python_ver: 3.9
@@ -107,8 +106,8 @@ jobs:
- desc: clang12/C++17 llvm12 oiio-master boost1.73 exr3.1 py3.9 avx2 batch-avx512
nametag: linux-clang12-llvm12-batch
os: ubuntu-latest
container: aswftesting/ci-osl:2022-clang12
vfxyear: 2022
vfxsuffix: -clang12
cxx_std: 17
openimageio_ver: master
python_ver: 3.9
@@ -116,11 +115,11 @@ jobs:
simd: avx2,f16c
batched: b8_AVX2,b8_AVX512,b16_AVX512
setenvs: USE_OPENVDB=0
- desc: icc/C++17 llvm13 py3.9 boost1.76 exr3.1 oiio-master avx2
- desc: icc/C++17 llvm14 py3.9 boost1.76 exr3.1 oiio-master avx2
nametag: linux-icc
os: ubuntu-latest
container: aswftesting/ci-osl:2022-clang14
vfxyear: 2022
vfxsuffix: -clang13
cc_compiler: icc
cxx_compiler: icpc
cxx_std: 17
@@ -133,11 +132,11 @@ jobs:
setenvs: export OSL_CMAKE_FLAGS="-DSTOP_ON_WARNING=OFF -DEXTRA_CPP_ARGS=-fp-model=consistent"
OPENIMAGEIO_CMAKE_FLAGS=-DBUILD_FMT_VERSION=7.1.3
USE_OPENVDB=0
- desc: icx/C++17 llvm13 py3.9 boost1.76 exr3.1 oiio2.3 avx2
- desc: icx/C++17 llvm14 py3.9 boost1.76 exr3.1 oiio2.3 avx2
nametag: linux-icx
os: ubuntu-latest
container: aswftesting/ci-osl:2022-clang14
vfxyear: 2022
vfxsuffix: -clang13
cc_compiler: icx
cxx_compiler: icpx
cxx_std: 17
@@ -148,13 +147,24 @@ jobs:
simd: avx2,f16c
batched: b8_AVX2_noFMA
setenvs: export OSL_CMAKE_FLAGS="-DSTOP_ON_WARNING=OFF" USE_OPENVDB=0
- desc: oldest everything gcc6/C++14 llvm9 py2.7 boost1.66 oiio2.2 no-simd exr2.3
- desc: gcc11/C++17 llvm15 py3.10 boost1.80 exr3.1 oiio-rel avx2
nametag: linux-vfx2023
os: ubuntu-latest
container: aswftesting/ci-osl:2023-clang15
vfxyear: 2023
cxx_std: 17
openimageio_ver: release
python_ver: "3.10"
pybind11_ver: v2.9.0
simd: avx2,f16c
batched: b8_AVX2
- desc: oldest everything gcc6/C++14 llvm9 py2.7 boost1.66 oiio2.3 no-simd exr2.3
nametag: linux-oldest
os: ubuntu-latest
container: aswftesting/ci-osl:2019-clang9
vfxyear: 2019
vfxsuffix: -clang9
cxx_std: 14
openimageio_ver: v2.3.17.0
openimageio_ver: v2.2.17.0
python_ver: 2.7
pybind11_ver: v2.6.2
simd: 0
@@ -164,8 +174,8 @@ jobs:
- desc: sanitizers
nametag: sanitizer
os: ubuntu-latest
container: aswftesting/ci-osl:2022-clang13
vfxyear: 2022
vfxsuffix: -clang13
cc_compiler: clang
cxx_compiler: clang++
cxx_std: 17
@@ -209,8 +219,8 @@ jobs:
- desc: "clang-format"
nametag: clang-format
os: ubuntu-latest
container: aswftesting/ci-osl:2022-clang14
vfxyear: 2022
vfxsuffix: -clang14
cxx_std: 17
openimageio_ver: release
python_ver: 3.9
@@ -222,7 +232,7 @@ jobs:
runs-on: ${{matrix.os}}
container:
image: aswftesting/ci-osl:${{matrix.vfxyear}}${{matrix.vfxsuffix}}
image: ${{ matrix.container }}
env:
CXX: ${{matrix.cxx_compiler}}
CC: ${{matrix.cc_compiler}}
@@ -292,11 +302,11 @@ jobs:
include:
- desc: Debug gcc7/C++14 llvm9 py2.7 oiio2.3 exr2.4 sse4 boost1.65 exr2.4
nametag: linux-debug-gcc7-llvm9
os: ubuntu-18.04
os: ubuntu-20.04
cxx_compiler: g++-7
cxx_std: 14
openexr_ver: v2.4.3
openimageio_ver: dev-2.3
openimageio_ver: v2.3.21.0
pybind11_ver: v2.6.2
python_ver: 2.7
simd: sse4.2
@@ -306,7 +316,7 @@ jobs:
CTEST_TEST_TIMEOUT=240
- desc: gcc10/C++17 llvm10 oiio-release boost1.65 exr2.5 avx2
nametag: linux-2021ish-gcc10-llvm10
os: ubuntu-18.04
os: ubuntu-20.04
cxx_compiler: g++-10
cxx_std: 17
fmt_ver: 7.0.1
@@ -320,20 +330,20 @@ jobs:
PUGIXML_VERSION=v1.10
- desc: latest releases gcc11/C++17 llvm13 boost1.71 exr3.1 py3.9 avx2 batch-b16avx512
nametag: linux-latest-releases
os: ubuntu-20.04
os: ubuntu-22.04
cxx_compiler: g++-11
cxx_std: 17
fmt_ver: 9.1.0
openexr_ver: v3.1.5
openexr_ver: v3.1.7
openimageio_ver: master
pybind11_ver: v2.10.0
python_ver: 3.9
python_ver: "3.10"
simd: avx2,f16c
batched: b8_AVX2,b8_AVX512,b16_AVX512
setenvs: export LLVM_VERSION=13.0.0
LLVM_DISTRO_NAME=ubuntu-20.04
OPENCOLORIO_VERSION=v2.1.2
PUGIXML_VERSION=v1.11.4
OPENCOLORIO_VERSION=v2.2.0
PUGIXML_VERSION=v1.13
- desc: bleeding edge gcc12/C++17 llvm14 oiio/ocio/exr/pybind-master boost1.71 py3.10 avx2 batch-b16avx512
nametag: linux-bleeding-edge
os: ubuntu-22.04
@@ -357,7 +367,7 @@ jobs:
cc_compiler: clang
cxx_std: 17
fmt_ver: 8.1.1
openexr_ver: v3.1.5
openexr_ver: v3.1.7
openimageio_ver: master
pybind11_ver: v2.9.2
python_ver: 3.8
@@ -437,6 +447,8 @@ jobs:
python_ver: "3.10"
aclang: 13
setenvs: export LLVMBREWVER="@14" DO_BREW_UPDATE=1
OPENIMAGEIO_VERSION=release
QT_BREW_VERSION="@5"
- desc: MacOS-12
os: macos-12
nametag: macos11-p310
@@ -446,6 +458,7 @@ jobs:
python_ver: "3.10"
aclang: 13
setenvs: export LLVMBREWVER="@15" DO_BREW_UPDATE=1
OPENIMAGEIO_VERSION=master
runs-on: ${{matrix.os}}
env:
CXX: ${{matrix.cxx_compiler}}
+8 -3
View File
@@ -10,18 +10,23 @@ on:
# Declare default permissions as read only.
permissions: read-all
# Allow subsequent pushes to the same PR or REF to cancel any previous jobs.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
analysis:
name: Scorecards analysis
if: |
github.repository == 'AcademySoftwareFoundation/OpenShadingLanguage'
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Used to receive a badge. (Upcoming feature)
id-token: write
# Needs for private repositories.
contents: read
actions: read
steps:
- name: "Checkout code"
+110 -56
View File
@@ -1,69 +1,118 @@
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
<!-- Copyright Contributors to the Open Shading Language Project. -->
Release 1.13 -- ?? 2023 ?? (compared to 1.12)
--------------------------------------------------
Dependency and standards requirements changes:
* OptiX 6.0 support has been removed. For GPU rendering with OptiX, a minimum
of OptiX 7.0 is required.
* The minimum version OpenImageIO has been raised from 2.2 to 2.3. #1591
(1.13.0.3)
Release 1.12.13.0 -- 1 July 2023 (compared to 1.12.12.0)
--------------------------------------------------------
- *fix*: Fix constant float values being converted to ints
[#1674](https://github.com/OpenImageIO/oiio/pull/1674) (by Declan Russell)
- *build* Fix builds when USE_PYTHON=OFF
[#1675](https://github.com/OpenImageIO/oiio/pull/1675) (by Declan Russell)
- *build* Changes to support fmt 10.0
[#1691](https://github.com/OpenImageIO/oiio/pull/1691)
- *cleanup* Switch deprecated oiio simd names to modern
[#1679](https://github.com/OpenImageIO/oiio/pull/1679)
- *testing*: Avoid deprecated OSLQuery ctr in test example
[#1699](https://github.com/OpenImageIO/oiio/pull/1699)
- *ci*: Fix package name for icc
[#1690](https://github.com/OpenImageIO/oiio/pull/1690)
- *ci*: Add VFX Platform 2023 tests using new ASWF containers
[#1696](https://github.com/OpenImageIO/oiio/pull/1696)
- *ci*: Switch oiio obsolete branch names to immutable tags
[#1701](https://github.com/OpenImageIO/oiio/pull/1701)
- *docs* Improve documentation of `trace` function
[#1671](https://github.com/OpenImageIO/oiio/pull/1671) (by AidanWelch)
- *docs* README.md: added filmography and Siggraph OSL course info.
[#1692](https://github.com/OpenImageIO/oiio/pull/1692)
[#1694](https://github.com/OpenImageIO/oiio/pull/1694) (by Mitch Prater)
- *docs* Amend the filmography
[#1695](https://github.com/OpenImageIO/oiio/pull/1695)
- *docs* Fix incorrect links in CONTRIBUTING
[#1688](https://github.com/OpenImageIO/oiio/pull/1688)
OSL Language and oslc compiler:
* Bug fix: shader params whose default values involve "init ops" could be
incorrectly initialized if their values came from instance parameters set to
zero. #1578 (1.13.0.2)
OSL Standard library:
Release 1.12.12.0 -- 1 May 2023 (compared to 1.12.11.0)
--------------------------------------------------------
* New ShadingSystem getattribute query for shader groups: "attribute_types"
retrieves a pointer to the array of TypeDesc values describing the
attributes retrieved by existing "attributes_needed" and "attribute_scopes".
#1650
* Fix a bug with binding userdata when it's used by more than one shader
within the group and they disagree about whether derivatives are needed when
retrieving the attribute. #1673
API changes, new options, new ShadingSystem features (for renderer writers):
* A new `shadingStateUniform` pointer field was added to ShaderGlobals for
planned future expansion and improved GPU support. #1585 (1.13.1.0)
Release 1.12.11.0 -- 5 Apr 2023 (compared to 1.12.10.0)
--------------------------------------------------------
* Build: Add Qt 6.x compatibility (Qt is only used for `osltoy`). #1655
* Build: more careful about paths to look for LLVM. #1656
* Build: Fix Cuda compilation flags for LLVM 15. #1659
* Notice: OSL does not yet build properly against the newly release LLVM 16.
You must use LLVM 9-15. For Mac users who get their llvm from Homebrew,
please be aware that Homebrew has changed its default llvm to 16, so you'll
need to `brew install llvm@14` and make your OSL CMake define:
`-DLLVM_ROOT=/usr/local/opt/llvm@14`
SIMD batched shading mode:
* Fix some array overruns (asymptomatic, but still potentially buggy) in
common_ancestor_between. #1577 (1.13.0.2)
Release 1.12.10.0 -- 1 Mar 2023 (compared to 1.12.9.0)
--------------------------------------------------------
* feat(testrender): Modify testrender so that it correctly sets raytype to
"camera" for camera rays, "shadow" for shadow rays, and "diffuse" for all
secondary rays. Also rerun the shades for background shader group on the
camera rays rather than use the cached map. This helps the MaterialX project
use testrender for certain unit tests and verification. #1648 #1649
* feat: Expose llvm groupdata size as a shadergroup attribute
"llvm_groupdata_size". #1642
* fix: Crash could result from uncaught exception in OpenColorIO when calling
transformc with derivatives for color spaces that require OCIO. #1646
* fix: certain uses of fmod() in shaders could fail to generate LLVM code
correctly, due to a missing implementation for the fmod(triple,float)
varieties. #1643
* build: Change snprintf formatting to satisfy some compilers. #1640
* CI: Fix broken Mac ci. #1647
OptiX rendering:
* OptiX 6.0 support has been removed. For GPU rendering with OptiX, a minimum
of OptiX 7.0 is required.
* Big overhaul/simplification of how strings are represented on the GPU: the
extra level of indirection to global variables is removed, and strings are
simply represented in ordinary variables as the hash of their characters.
#1531 (1.13.0.0) #1553 (1.13.0.1)
* Better PTX cache hit rate by eliminating several sources of not being
strictly deterministic in the PTX text we were generating. #1566 #1570
(1.13.0.1)
Release 1.12.9.0 -- 1 Feb 2023 (compared to 1.12.8.0)
-------------------------------------------------------
* Remove unnecessary setting of locale::global. #1630
* Batch shading: Fix bug with masked wide closure generation. #1637
* Make sure ReParameter() has the same relaxed type checking rules as
Parameter(). Before, it was stricter about type conversion. #1639
* Windows: Fix some GPU build errors. #1638
Performance improvements:
Release 1.12.8.0 -- 3 Jan 2023 (compared to 1.12.7.1)
-------------------------------------------------------
* Remove dependency on OptiX SDK for building core OSL with OptiX support.
You can now build OSL with OptiX support enabled even if you don't have the
OptiX SDK headers present at build time. But you will still need them to
build your OptiX-based application that uses OSL for GPU rendering. #1627
* Batch mode: fix issue with closure keyword parameters. #1620
* Batch mode: fix crash when adding a default initialized closure. #1624
* Batch mode: Fix support for closures with array types. #1630
* testshade: better testing of all closure parameter types. #1621
* Fix various CI breaks as dependencies shifted. #1629 #1631 #1633
Bug fixes and other improvements (internals):
* Fix memory leak in oslc ASTvariable_declaration. #1576 (1.13.0.2)
* Fix memory leaks in LPE code in error conditions. #1593 #1594 (1.13.0.3)
Internals/developer concerns:
* platform.h:
- New `OSL_ALLOCA` macro to allocate on the stack. #1589 (1.13.0.3)
Build & test system improvements:
* CMake build system and scripts:
- The version number is now a cache variable, and so can be overridden at
build time using `-DOSL_VERSION=...`. Use with extreme caution! #1579
(1.13.0.2)
* Dependency version support:
- Fix some issues that came up with the new icx 2022.0 compiler. #1601
(1.13.1.0)
* Testing and Continuous integration (CI) systems:
- Dynamic analysis using address and leak sanitizers. #1581 (1.13.0.3)
- `testshade --help` now prints TextureSystem options and all hardware
information. #1584 (1.13.0.3)
- Improvements to SonarCloud and coverage analysis. #1596 (1.13.0.3)
* Platform support:
Documentation:
* `doc/RELEASING.md` documents our release process and versioning policies.
#1572 (1.13.0.2)
Release 1.12.7.1 -- 1 Dec 2022 (compared to 1.12.7.0)
-------------------------------------------------------
* Add clangSupport library as dependency to fix linker error on some
platforms. #1613
* Test against OpenColorIO 2.2. #1616
* Build: Fix how version overrides work to reduce the chance of user mistakes.
#1617
Release 1.12.7.0 -- 1 Nov 2022 (compared to 1.12.6.2)
-------------------------------------------------------
* Optix: Change naming of certain compiler-generated constants in a way that
improves use of the PTX cache. #1570
* Batch: Fix uninitialized members in ReadEvent internals. #1575
* `testshade --help` now prints TextureSystem options and hardware info. #1584
* oslc: Fix memory leak in ASTvariable_declaration. #1576
* Fix memory leaks in light path expression code. #1593 #1594
* Include the immintrin.h header only when needed. #1605
* icx: Improvements to fix problems exposed by new icx 2022.2 compiler. #1601
* Testing: CMake cache variables to control the testing timeout length. #1571
* CI: Add a dynamic analysis test using address and leak sanitizers. #1581
* CI: Now using SonarCloud static analysis. #1551
* CI: Many improvements in testing code coverage #1607
* CI: Make sure to run pointcloud tests when partio is found. #1611
* Developers: platform.h now defines OSL_ALLOCA macro. #1589
* Developers: platform.h now defines OSL::bitcast utility. #1610
Release 1.12 -- 1 Oct 2022 (compared to 1.11)
----------------------------------------------
@@ -161,7 +210,9 @@ SIMD batched shading mode:
* Batched isnan, isinf, isfinite. #1456 (1.12.4.2)
* Batched userdata and output placement. #1455 (1.12.4.2)
* Batched pointcloud functions. #1464 (1.12.4.4)
* Batched closures (#1500)
* Batched closures #1500
* Fix overrunning allocation region in debug common_ancestor_between. #1577
(1.12.6.1)
OptiX rendering:
* Explicitly set the OptiX pipeline stack size. #1254 (1.12.0.0)
@@ -231,6 +282,8 @@ Bug fixes and other improvements (internals):
* Switch to cone tracing for derivatives. #1543 (1.12.6.0)
* Fix error that prevented correct typecheck of ternary operator. #1552
(1.12.6.0)
* Fix bug where assigning an init-op param its default value as an instance
value would get lost. #1578 (1.12.6.1)
Internals/developer concerns:
* Use the `final` keyword in certain internal classes where applicable.
@@ -299,6 +352,7 @@ Build & test system improvements:
(1.12.4.1)
- Make exported cmake configs relocatable by using relative paths. #1466
(1.12.4.4)
- Make the version number be a cmake cache variable. #1579 (1.12.6.1)
* Dependency version support:
- Build properly against Cuda 11 and OptiX 7.1. #1232 (1.12.0.1)
and up to OptiX 7.4 #1559 (1.12.6.0)
+15 -4
View File
@@ -4,19 +4,26 @@
cmake_minimum_required (VERSION 3.12)
set (OSL_VERSION "1.13.1.0" CACHE STRING "Version")
set (OSL_VERSION "1.12.13.0")
set (OSL_VERSION_OVERRIDE "" CACHE STRING
"Version override (use with caution)!")
mark_as_advanced (OSL_VERSION_OVERRIDE)
if (OSL_VERSION_OVERRIDE)
set (OSL_VERSION ${OSL_VERSION_OVERRIDE})
endif ()
project (OSL VERSION ${OSL_VERSION}
LANGUAGES CXX C
HOMEPAGE_URL "https://github.com/AcademySoftwareFoundation/OpenShadingLanguage")
set (PROJ_NAME ${PROJECT_NAME}) # short name
string (TOLOWER ${PROJ_NAME} PROJ_NAME_LOWER) # short name lower case
string (TOUPPER ${PROJ_NAME} PROJ_NAME_UPPER) # short name upper case
set (PROJECT_VERSION_RELEASE_TYPE "dev" CACHE STRING
set (PROJECT_VERSION_RELEASE_TYPE "" CACHE STRING
"Build type, for example: dev, beta2, RC1 (empty string for normal release)")
set (${PROJECT_NAME}_VERSION_RELEASE_TYPE ${PROJECT_VERSION_RELEASE_TYPE})
set (PROJECT_AUTHORS "Contributors to the Open Shading Language project")
option (${PROJECT_NAME}_SUPPORTED_RELEASE
"Set ON for supported release branch, OFF for master" OFF)
"Set ON for supported release branch, OFF for master" ON)
if (${PROJECT_NAME}_SUPPORTED_RELEASE)
set (${PROJECT_NAME}_DEV_RELEASE OFF)
else ()
@@ -127,6 +134,10 @@ endif ()
# defined for downstream projects using OSL.
add_definitions (-DOSL_INTERNAL=1)
# To make sure we aren't relying on deprecated OIIO features, we define
# OIIO_DISABLE_DEPRECATED before including any OIIO headers.
add_definitions (-DOIIO_DISABLE_DEPRECATED=1)
# Set the default namespace. For symbol hiding reasons, it's important that
# the project name is a subset of the namespace name.
set (${PROJ_NAME}_NAMESPACE ${PROJECT_NAME} CACHE STRING
@@ -214,7 +225,7 @@ if (OSL_BUILD_PLUGINS)
add_subdirectory (src/osl.imageio)
endif ()
if (USE_QT AND Qt5_FOUND)
if (USE_QT AND (Qt5_FOUND OR Qt6_FOUND))
add_subdirectory (src/osltoy)
endif ()
+2 -2
View File
@@ -55,13 +55,13 @@ Contributor License Agreement (CLA) and Intellectual Property
To protect the project -- and the contributors! -- we do require a
Contributor License Agreement (CLA) for anybody submitting changes.
* [Corporate CLA](https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/ASWF/OSL-CLA-corporate.md)
* [Corporate CLA](https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/blob/main/ASWF/CLA-corporate.md)
If you are writing the code as part of your job, or if there is any
possibility that your employers might think they own any intellectual
property you create. This needs to be executed by someone who has
signatory power for the company.
* [Individual]((https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/ASWF/OSL-CLA-individual.md)).
* [Individual CLA](https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/blob/main/ASWF/CLA-individual.md).
If you are an individual writing the code on your own time and you're SURE
you are the sole owner of any intellectual property you contribute.
+17 -15
View File
@@ -12,16 +12,16 @@ 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.12 or newer (tested through 3.24)
* Build system: [CMake](https://cmake.org/) 3.12 or newer (tested through 3.26)
* A suitable C++14 or C++17 compiler to build OSL itself, which may be any of:
- GCC 6.1 or newer (tested through gcc 12.1)
- Clang 3.4 or newer (tested through clang 15)
- Microsoft Visual Studio 2017 or newer
- Intel C++ compiler icc version 17 or newer or LLVM-based icx compiler
version 2022 or newer.
* A suitable **C++14 or C++17** compiler to build OSL itself, which may be any of:
- **GCC 6.1 or newer** (tested through gcc 12.1)
- Clang 3.4 or newer (tested through clang 16)
- Microsoft Visual Studio **2017 or newer**
- Intel C++ compiler icc **version 17 or newer** or LLVM-based icx compiler
**version 2022 or newer**.
* **[OpenImageIO](http://openimageio.org) 2.3 or newer** (tested through 2.4)
* **[OpenImageIO](http://openimageio.org) 2.2 or newer** (tested through 2.4)
OSL uses OIIO both for its texture mapping functionality as well as
numerous utility classes. If you are integrating OSL into an existing
@@ -40,14 +40,16 @@ NEW or CHANGED dependencies since the last major release are **bold**.
$OpenImageIO_ROOT/lib to be in your LD_LIBRARY_PATH (or
DYLD_LIBRARY_PATH on OS X).
* [LLVM](http://www.llvm.org) 9, 10, 11, 12, 13, 14, or 15, including
clang libraries.
* **[LLVM](http://www.llvm.org) 9, 10, 11, 12, 13, 14, or 15**, including
clang libraries. LLVM 16 doesn't work yet, we need to make changes
on the OSL side to be compatible.
* (optional) For GPU rendering on NVIDIA GPUs:
* [OptiX](https://developer.nvidia.com/rtx/ray-tracing/optix) 7.0 or higher.
* [Cuda](https://developer.nvidia.com/cuda-downloads) 8.0 or higher.
* [OptiX](https://developer.nvidia.com/rtx/ray-tracing/optix) 5.1 or higher
(though 7.0+ is highly recommended).
* [Boost](https://www.boost.org) 1.55 or newer (tested through boost 1.80)
* [Boost](https://www.boost.org) 1.55 or newer (tested through boost 1.81)
* [Ilmbase or Imath](https://github.com/AcademySoftwareFoundation/openexr) 2.3
or newer (recommended: 2.4 or higher; tested through 3.1)
* [Flex](https://github.com/westes/flex) 2.5.35 or newer and
@@ -55,7 +57,7 @@ NEW or CHANGED dependencies since the last major release are **bold**.
Note that on some MacOS/xcode releases, the system-installed Bison is too
old, and it's better to install a newer Bison (via Homebrew is one way to
do this easily).
* [PugiXML](http://pugixml.org/)
* [PugiXML](http://pugixml.org/) >= 1.8 (we have tested through 1.13).
* (optional) [Partio](https://www.disneyanimation.com/technology/partio.html)
If it is not found at build time, the OSL `pointcloud` functions will not
be operative.
@@ -64,8 +66,8 @@ NEW or CHANGED dependencies since the last major release are **bold**.
* Python >= 2.7 (tested against 2.7, 3.7, 3.8, 3.9, 3.10)
* pybind11 >= 2.4.2 (Tested through 2.10)
* NumPy
* (optional) Qt >= 5.6 (tested through 5.15). If not found at build time,
the `osltoy` application will be disabled.
* (optional) Qt5 >= 5.6 or Qt6 (tested Qt5 through 5.15 and Qt6 through 6.4).
If not found at build time, the `osltoy` application will be disabled.
+60 -23
View File
@@ -219,14 +219,15 @@ inferred from public sources, or that we've been told is ok to list here. If
an OSL-using project is missing and it's not a secret, just email the OSL
project leader or submit a PR with edits to this file.*
Renderers and other tools with OSL support (in approximate order of
adding OSL support):
* Sony Pictures Imageworks: in-house "Arnold" renderer
### Renderers and other production tools with OSL support
(In approximate order of adding OSL support)
* [Sony Pictures Imageworks: in-house "Arnold" renderer](https://dl.acm.org/doi/10.1145/3180495)
* [Blender/Cycles](https://docs.blender.org/manual/en/dev/render/shader_nodes/osl.html)
* [Chaos Group: V-Ray](https://www.chaosgroup.com/)
* [Pixar: PhotoRealistic RenderMan RIS](https://renderman.pixar.com)
* [Isotropix: Clarisse](http://www.isotropix.com/clarisse)
* [Isotropix: Angie](http://www.isotropix.com/angie)
* Isotropix: [Clarisse iFX](https://www.isotropix.com/products/clarisse/ifx) / [Clarisse BUiLDER](https://www.isotropix.com/products/clarisse/builder) / [Angie](https://www.isotropix.com/products/angie)
* [Autodesk Beast](http://www.autodesk.com/products/beast/overview)
* [Appleseed](http://appleseedhq.net)
* [Animal Logic: Glimpse renderer](https://www.fxguide.com/featured/a-glimpse-at-animal-logic/)
@@ -237,7 +238,13 @@ adding OSL support):
* [Autodesk: 3DS Max 2019](https://help.autodesk.com/view/3DSMAX/2019/ENU/?guid=__developer_3ds_max_sdk_features_rendering_osl_html)
* [Maxon: Redshift](https://www.maxon.net/en/redshift)
Films using OSL (grouped by year of release date):
### Significant work using OSL, grouped by year of release date:
(Here we are considering "significant work" to mean a feature film released
theatrically or on a major streaming platform, TV/streaming series heavily
featuring visual effects or animation, or short films that have won or been
nominated for major awards.)
* **(2012)**
Men in Black 3, The Amazing Spider-Man, Hotel Transylvania
* **(2013)**
@@ -272,6 +279,7 @@ Films using OSL (grouped by year of release date):
Ghostbusters,
Star Trek Beyond,
Suicide Squad,
Kubo and the Two Strings,
Kingsglaive: Final Fantasy XV,
Storks,
Miss Peregrine's Home for Peculiar Children,
@@ -306,7 +314,7 @@ Films using OSL (grouped by year of release date):
* **(2018)**
Peter Rabbit,
Black Panther,
Annnihilation,
Annihilation,
Red Sparrow,
Pacific Rim Uprising,
Avengers Infinity War,
@@ -354,7 +362,8 @@ Films using OSL (grouped by year of release date):
Richard Jewell,
Game of Thrones (S8),
Lost in Space (S1),
Togo
Togo,
Missing Link
* **(2020)**
Underwater,
Birds of Prey,
@@ -370,7 +379,9 @@ Films using OSL (grouped by year of release date):
Over the Moon,
Wonder Woman 1984,
Soul,
The Mandalorian (S2)
The Mandalorian (S2),
The Boys (S2),
Umbrella Academy (S2)
* **(2021)**
Chaos Walking,
Peter Rabbit 2: The Runaway,
@@ -383,6 +394,7 @@ Films using OSL (grouped by year of release date):
F9,
Vivo,
Jungle Cruise,
Cinderella,
Dune,
No Time To Die,
Ron's Gone Wrong,
@@ -390,8 +402,9 @@ Films using OSL (grouped by year of release date):
Last Night in Soho,
Ghostbusters: Afterlife,
Spider-Man 3: No Way Home,
Matrix Resurrections
* **(2022 / upcoming)**
Matrix Resurrections,
Sing 2
* **(2022)**
Hotel Transylvania 4: Transformania,
Death on the Nile,
Uncharted,
@@ -404,11 +417,26 @@ Films using OSL (grouped by year of release date):
Thor: Love and Thunder,
The Sea Beast,
DC League of Super Pets,
Minions: Rise of Gru,
Bullet Train,
Slumberland,
Glass Onion,
Archive 81 (series),
Moon Night (series),
Obi-Wan Kenobi (series),
The Boys (S3),
Andor (S1)
* **(2023 / upcoming)**
Ant-Man and the Wasp: Quantumania,
The Mandalorian S3,
The Magician's Elephant,
Super Mario Bros Film,
Guardians of the Galaxy 3,
Spider-Man: Across the Spider-Verse,
Elemental,
...
Building and Installation
-------------------------
@@ -424,6 +452,13 @@ The OSL language specification can be found at
distribution) or in the share/doc/OSL/osl-languagespec.pdf file of an
installed binary distribution.
For those interested in learning to program in OSL, there is the
[Siggraph 2022 Educator's Forum](https://dl.acm.org/doi/proceedings/10.1145/3532724)
[OSL Shaders for RenderMan](https://dl.acm.org/doi/abs/10.1145/3532724.3535604) course,
which uses RenderMan in the examples and
[Supplementary Materials](https://github.com/LaikaStudios/OSLShadersForRenderMan),
but which is primarily about shader writing in OSL.
Contact & reporting problems
----------------------------
@@ -481,18 +516,20 @@ The current project leadership is documented in the
Many people have contributed features, bug fixes, and other changes to OSL
over the years: Steve Agland, Shane Ambler, Martijn Berger, Farchad
Bidgolirad, Nicholas Bishop, Solomon Boulos, Stefan Bruens, Stefan Büttner,
Matthaus G. Chajdas, Clark Chen, Alejandro Conty, Dieter De Baets, Thomas
Dinges, Mads Drøschler, Luke Emrose, Louis Feng, Mark Final, Henri Fousse,
Stephen Friedman, Syoyo Fujita, Tim Grant, Larry Gritz, Nicolas Guiard, Euan
Haahr, Derek Haase, Sven-Hendrik Haase, John Haddon, Niklas Harrysson, Daniel
Heckenberg, Adrien Herubel, Thiago Ize, Matt Johnson, Ronan Keryell, Chris
Matthaus G. Chajdas, Clark Chen, Alejandro Conty, Damien Courtois, Dieter De
Baets, Thomas Dinges, Daniel Dresser, Mads Drøschler, Peter Ellerington, Luke
Emrose, Louis Feng, Mark Final, Henri Fousse, Stephen Friedman, Syoyo Fujita,
Tim Grant, Larry Gritz, Nicolas Guiard, Euan Haahr, Derek Haase, Sven-Hendrik
Haase, John Haddon, Niklas Harrysson, Daniel Heckenberg, Chris Hellmuth,
Adrien Herubel, Dan Horák, Thiago Ize, Matt Johnson, Ronan Keryell, Chris
Kulla, Elvic Liang, Max Liani, Adam Martinez, John Mertic, Bastien Montagne,
Steena Monteiro, Alexis Oblet, Erich Ocean, Mikko Ohtamaa, Jino Park, Alexei
Pawlow, Jay Reynolds, Declan Russell, Benoit Ruiz, Patrick Scheibe, Alex
Schworer, Jonathan Scruggs, Sergey Sharybin, Sandip Shukla, Cliff Stein,
Stephan Steinbach, Luya Tshimbalanga, Esteban Tovagliari, Brecht Van Lommel,
Alexander von Knorring, Alex Wells, Roman Zulak. (Listed alphabetically; if
we've left anybody out, it is inadvertent, please let us know.)
Steena Monteiro, Patrick Mours, Alexis Oblet, Erich Ocean, Mikko Ohtamaa, Jino
Park, Alexei Pawlow, Jay Reynolds, Declan Russell, Benoit Ruiz, Patrick
Scheibe, Alex Schworer, Jonathan Scruggs, Sergey Sharybin, Mark Sisson, Sandip
Shukla, Cliff Stein, Stephan Steinbach, Luya Tshimbalanga, Esteban Tovagliari,
Brecht Van Lommel, Alexander von Knorring, Alex Wells, Roman Zulak. (Listed
alphabetically; if we've left anybody out, it is inadvertent, please let us
know.)
We cannot possibly express sufficient gratitude to the managers at Sony
Pictures Imageworks who allowed this project to proceed, supported it
+7 -2
View File
@@ -144,7 +144,8 @@ branch, and henceforth, any big or compatibility-breaking changes will only be
committed to main and not backported to the release branch. (Though we are
loose about this rule during the alpha period and allow continued breaking
changes in the alpha, but by the time we call it beta, we allow no more
breaking changes.)
breaking changes.) Also at this stage, the main branch's CHANGES.md should
have a heading added at the top for the *next* version.
### Prior to a release
@@ -338,4 +339,8 @@ Odds and ends to do after the tag is pushed and the announcements are sent:
Language" channel of the ASWF slack. It can be a one-line announcement and
then just a link to the GitHub release page for this version.
- Edit the top-level CMakeList.txt to update the version to the *next*
anticipated release on the branch, in order to ensure that anybody building
from subsequent patches won't get a release number that advertises itself
incorrectly as a prior tagged release. Also edit CHANGES.md to add a new
(blank) heading for the next patch or release.
+8 -4
View File
@@ -189,6 +189,10 @@ else ifeq (${platform}, macosx)
MY_CMAKE_FLAGS += \
-DCMAKE_C_COMPILER=/usr/local/opt/llvm@15/bin/clang \
-DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@15/bin/clang++
else ifeq (${COMPILER},clang16)
MY_CMAKE_FLAGS += \
-DCMAKE_C_COMPILER=/usr/local/opt/llvm@16/bin/clang \
-DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@16/bin/clang++
else ifeq (${COMPILER},clang)
MY_CMAKE_FLAGS += -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
else ifeq (${COMPILER},gcc)
@@ -196,13 +200,13 @@ else ifeq (${platform}, macosx)
else ifeq (${COMPILER},)
# default compiler is clang, taken from the LLVM directory
MY_CMAKE_FLAGS += \
-DCMAKE_C_COMPILER=${LLVM_DIRECTORY}/bin/clang \
-DCMAKE_CXX_COMPILER=${LLVM_DIRECTORY}/bin/clang++
-DCMAKE_C_COMPILER=${LLVM_ROOT}/bin/clang \
-DCMAKE_CXX_COMPILER=${LLVM_ROOT}/bin/clang++
else ifeq (${COMPILER},llvm)
# "llvm" means "use the clang from our llvm"
MY_CMAKE_FLAGS += \
-DCMAKE_C_COMPILER=${LLVM_DIRECTORY}/bin/clang \
-DCMAKE_CXX_COMPILER=${LLVM_DIRECTORY}/bin/clang++
-DCMAKE_C_COMPILER=${LLVM_ROOT}/bin/clang \
-DCMAKE_CXX_COMPILER=${LLVM_ROOT}/bin/clang++
endif
# end generic OSX
-1
View File
@@ -18,7 +18,6 @@ sonar.links.issue=https://github.com/AcademySoftwareFoundation/OpenShadingLangua
# Source properties
sonar.sources=src
sonar.sourceEncoding=UTF-8
sonar.exclusions=src/include/OSL/Imath/*.h,src/build-scripts/*
# C/C++ analyzer properties
sonar.cfamily.build-wrapper-output=build/bw_output
+1 -1
View File
@@ -14,7 +14,7 @@ uname
if [[ `uname` == "Linux" ]] ; then
LLVM_VERSION=${LLVM_VERSION:=13.0.0}
LLVM_VERSION=${LLVM_VERSION:=14.0.0}
LLVM_INSTALL_DIR=${LLVM_INSTALL_DIR:=${PWD}/llvm-install}
if [[ "$GITHUB_WORKFLOW" != "" ]] ; then
LLVM_DISTRO_NAME=${LLVM_DISTRO_NAME:=ubuntu-18.04}
-9
View File
@@ -12,15 +12,6 @@ pushd _coverage
ls -R ../build/src/
# Remove files or directories we want to exclude from code coverage analysis,
# generally because we don't expect to execute any of their code during our
# CI. (Because it's only used interactively, or is fallback code only used
# when certain dependencies are not found.) Including these when we know we
# won't be calling them during coverage gathering will just make our coverage
# percentage look artifically low.
rm -f ../build/src/osltoy/CMakeFiles/osltoy.dir/*.cpp.{gcno,gcda}
# The sed command below converts from:
# ../build/src/liboslexec/CMakeFiles/oslexec.dir/foo.gcno
# to:
-1
View File
@@ -61,7 +61,6 @@ echo "uname -a: " `uname -a`
echo "uname -m: " `uname -m`
echo "uname -s: " `uname -s`
echo "uname -n: " `uname -n`
echo "nproc " `nproc`
pwd
ls
env | sort
+11 -6
View File
@@ -18,8 +18,8 @@ if [[ "$ASWF_ORG" != "" ]] ; then
#ls /etc/yum.repos.d
sudo yum install -y giflib giflib-devel && true
# sudo yum install -y ffmpeg ffmpeg-devel && true
sudo /usr/bin/yum install -y giflib giflib-devel && true
# sudo /usr/bin/yum install -y ffmpeg ffmpeg-devel && true
if [[ "${CONAN_LLVM_VERSION}" != "" ]] ; then
mkdir conan
@@ -42,7 +42,7 @@ if [[ "$ASWF_ORG" != "" ]] ; then
if [[ "$CXX" == "icpc" || "$CC" == "icc" || "$USE_ICC" != "" || "$CXX" == "icpx" || "$CC" == "icx" || "$USE_ICX" != "" ]] ; then
sudo cp src/build-scripts/oneAPI.repo /etc/yum.repos.d
sudo yum install -y intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic-2022.1.0-3768
sudo /usr/bin/yum install -y intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic-2022.1.0.x86_64
# Because multiple (possibly newer) versions of oneAPI may be installed,
# use a config file to specify compiler and tbb versions
# NOTE: oneAPI components have independent version numbering.
@@ -61,7 +61,7 @@ if [[ "$ASWF_ORG" != "" ]] ; then
else
# Using native Ubuntu runner
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
# sudo add-apt-repository ppa:ubuntu-toolchain-r/test
time sudo apt-get update
time sudo apt-get -q install -y \
@@ -73,8 +73,13 @@ else
libpugixml-dev \
libopencolorio-dev
time sudo apt-get -q install -y \
qt5-default || /bin/true
if [[ "${QT_VERSION:-5}" == "5" ]] ; then
time sudo apt-get -q install -y \
qt5-default || /bin/true
elif [[ "${QT_VERSION}" == "6" ]] ; then
time sudo apt-get -q install -y \
qt6-base-dev || /bin/true
fi
export CMAKE_PREFIX_PATH=/usr/lib/x86_64-linux-gnu:$CMAKE_PREFIX_PATH
+8 -6
View File
@@ -19,6 +19,7 @@ if [[ `which brew` == "" ]] ; then
exit 1
fi
set -ex
if [[ "$DO_BREW_UPDATE" != "" ]] ; then
brew update >/dev/null
@@ -30,20 +31,21 @@ brew list --versions
brew install --display-times -q gcc ccache cmake ninja boost || true
brew link --overwrite gcc
brew install --display-times -q python@${PYTHON_VERSION} || true
brew unlink python@2.7 || true
brew unlink python@3.8 || true
brew unlink python@3.9 || true
# brew unlink python@2.7 || true
# brew unlink python@3.8 || true
# brew unlink python@3.9 || true
brew unlink python@3.10 || true
brew link --overwrite --force python@${PYTHON_VERSION} || true
brew upgrade --display-times -q cmake || true
brew install --display-times -q ilmbase openexr
brew install --display-times -q imath openexr
#brew install --display-times -q freetype
brew install --display-times -q opencolorio partio pugixml
brew install --display-times -q --overwrite --force opencolorio || true
brew install --display-times -q partio pugixml
brew install --display-times -q pybind11 numpy || true
brew install --display-times -q tbb || true
brew install --display-times -q flex bison
brew install --display-times -q llvm${LLVMBREWVER}
brew install --display-times -q qt
brew install --display-times -q qt${QT_BREW_VERSION}
echo ""
echo "After brew installs:"
+6
View File
@@ -21,6 +21,12 @@ function ( NVCC_COMPILE cuda_src extra_headers ptx_generated extra_nvcc_args )
list (TRANSFORM OpenImageIO_INCLUDES PREPEND -I
OUTPUT_VARIABLE ALL_OpenImageIO_INCLUDES)
if (${LLVM_VERSION} VERSION_GREATER_EQUAL 15.0)
# Until we fully support opaque pointers, we need to disable
# them when using LLVM 15.
list (APPEND LLVM_COMPILE_FLAGS -Xclang -no-opaque-pointers)
endif ()
add_custom_command ( OUTPUT ${cuda_ptx}
COMMAND ${CUDA_NVCC_EXECUTABLE}
"-I${OPTIX_INCLUDES}"
+55 -39
View File
@@ -105,7 +105,7 @@ endif ()
# OpenImageIO
checked_find_package (OpenImageIO REQUIRED
VERSION_MIN 2.3.17
VERSION_MIN 2.2.6
DEFINITIONS -DOIIO_HIDE_FORMAT=1)
checked_find_package (pugixml REQUIRED
@@ -115,6 +115,7 @@ checked_find_package (pugixml REQUIRED
# LLVM library setup
checked_find_package (LLVM REQUIRED
VERSION_MIN 9.0
VERSION_MAX 15.9
PRINT LLVM_SYSTEM_LIBRARIES CLANG_LIBRARIES)
# ensure include directory is added (in case of non-standard locations
include_directories (BEFORE SYSTEM "${LLVM_INCLUDES}")
@@ -144,6 +145,19 @@ if (LLVM_VERSION VERSION_GREATER_EQUAL 15.0
"If you are using LLVM 15 or higher, you should also use clang version "
"15 or higher, or you may get build errors.${ColorReset}\n")
endif ()
if (LLVM_VERSION VERSION_GREATER_EQUAL 16.0)
message (ERROR "${ColorYellow}OSL is not yet compatible with LLVM 16.${ColorReset}\n")
if (CMAKE_CXX_STANDARD VERSION_LESS 17)
message (WARNING "${ColorYellow}LLVM 16+ requires C++17 or higher. "
"Please set CMAKE_CXX_STANDARD to 17 or higher.${ColorReset}\n")
endif ()
if (CMAKE_COMPILER_IS_GNUCC AND (GCC_VERSION VERSION_LESS 7.0))
message (WARNING "${ColorYellow}LLVM 16+ requires gcc 7.0 or higher.${ColorReset}\n")
endif ()
if (CMAKE_COMPILER_IS_CLANG AND (CLANG_VERSION_STRING VERSION_LESS 5.0))
message (WARNING "${ColorYellow}LLVM 16+ requires clang 5.0 or higher.${ColorReset}\n")
endif ()
endif ()
checked_find_package (partio)
@@ -153,60 +167,63 @@ find_python ()
# Qt -- used for osltoy
set (qt5_modules Core Gui Widgets)
if (OPENGL_FOUND)
list (APPEND qt5_modules OpenGL)
endif ()
option (USE_QT "Use Qt if found" ON)
checked_find_package (Qt5 COMPONENTS ${qt5_modules})
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")
if (USE_QT)
checked_find_package (Qt6 COMPONENTS Core Gui Widgets OpenGLWidgets)
if (NOT Qt6_FOUND)
checked_find_package (Qt5 COMPONENTS Core Gui Widgets OpenGL)
endif ()
if (NOT Qt5_FOUND AND NOT Qt6_FOUND AND APPLE)
message (STATUS " If you think you installed qt with Homebrew and it still doesn't work,")
message (STATUS " try: export PATH=/usr/local/opt/qt/bin:$PATH")
endif ()
endif ()
# 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 (USE_LLVM_BITCODE)
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 ()
if (NOT CUDA_FIND_QUIETLY OR NOT OptiX_FIND_QUIETLY)
message (STATUS "CUDA_TOOLKIT_ROOT_DIR = ${CUDA_TOOLKIT_ROOT_DIR}")
endif ()
checked_find_package (CUDA REQUIRED
VERSION_MIN 8.0
PRINT CUDA_INCLUDES)
set (CUDA_INCLUDES ${CUDA_TOOLKIT_ROOT_DIR}/include)
include_directories (BEFORE "${CUDA_INCLUDES}")
checked_find_package (CUDA REQUIRED
VERSION_MIN 8.0
PRINT CUDA_INCLUDES)
set (CUDA_INCLUDES ${CUDA_TOOLKIT_ROOT_DIR}/include)
include_directories (BEFORE "${CUDA_INCLUDES}")
STRING (FIND ${LLVM_TARGETS} "NVPTX" nvptx_index)
if (NOT ${nvptx_index} GREATER -1)
message (FATAL_ERROR "NVPTX target is not available in the provided LLVM build")
endif()
STRING (FIND ${LLVM_TARGETS} "NVPTX" nvptx_index)
if (NOT ${nvptx_index} GREATER -1)
message (FATAL_ERROR "NVPTX target is not available in the provided LLVM build")
endif()
set (CUDA_LIB_FLAGS "--cuda-path=${CUDA_TOOLKIT_ROOT_DIR}")
set (CUDA_LIB_FLAGS "--cuda-path=${CUDA_TOOLKIT_ROOT_DIR}")
find_library(cuda_lib NAMES cudart
PATHS "${CUDA_TOOLKIT_ROOT_DIR}/lib64" "${CUDA_TOOLKIT_ROOT_DIR}/x64"
REQUIRED)
set(CUDA_LIBRARIES ${cuda_lib})
find_library(cuda_lib NAMES cudart
PATHS "${CUDA_TOOLKIT_ROOT_DIR}/lib64" "${CUDA_TOOLKIT_ROOT_DIR}/x64" "${CUDA_TOOLKIT_ROOT_DIR}/lib/x64"
REQUIRED)
set(CUDA_LIBRARIES ${cuda_lib})
# testrender & testshade need libnvrtc
if ("${CUDA_VERSION}" VERSION_GREATER_EQUAL "10.0")
find_library(nvrtc_lib NAMES nvrtc
PATHS "${CUDA_TOOLKIT_ROOT_DIR}/lib64" "${CUDA_TOOLKIT_ROOT_DIR}/x64"
REQUIRED)
set(CUDA_LIBRARIES ${CUDA_LIBRARIES} ${nvrtc_lib})
# testrender & testshade need libnvrtc
if ("${CUDA_VERSION}" VERSION_GREATER_EQUAL "10.0")
find_library(nvrtc_lib NAMES nvrtc
PATHS "${CUDA_TOOLKIT_ROOT_DIR}/lib64" "${CUDA_TOOLKIT_ROOT_DIR}/x64" "${CUDA_TOOLKIT_ROOT_DIR}/lib/x64"
REQUIRED)
set(CUDA_LIBRARIES ${CUDA_LIBRARIES} ${nvrtc_lib})
set(CUDA_EXTRA_LIBS ${CUDA_EXTRA_LIBS} dl)
set(CUDA_EXTRA_LIBS ${CUDA_EXTRA_LIBS} dl)
endif()
endif()
# OptiX setup
if (USE_OPTIX)
if (USE_OPTIX AND OSL_BUILD_TESTS)
checked_find_package (OptiX REQUIRED
VERSION_MIN 7.0)
VERSION_MIN 5.1)
include_directories (BEFORE "${OPTIX_INCLUDES}")
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")
@@ -219,7 +236,6 @@ if (USE_CUDA OR USE_OPTIX)
target_compile_definitions (${TARGET} PRIVATE "-DPTX_PATH=\"${OSL_PTX_INSTALL_DIR}\"")
target_link_libraries (${TARGET} PRIVATE ${CUDA_LIBRARIES} ${CUDA_EXTRA_LIBS} ${OPTIX_LIBRARIES} ${OPTIX_EXTRA_LIBS})
endfunction()
else ()
function (osl_optix_target TARGET)
endfunction()
+8 -2
View File
@@ -23,7 +23,13 @@
# try to find llvm-config, with a specific version if specified
if (LLVM_DIRECTORY)
set (LLVM_CONFIG_PATH_HINTS "${LLVM_DIRECTORY}/bin")
list (APPEND LLVM_CONFIG_PATH_HINTS "${LLVM_DIRECTORY}/bin")
endif ()
if (LLVM_ROOT)
list (APPEND LLVM_CONFIG_PATH_HINTS "${LLVM_ROOT}/bin")
endif ()
if (DEFINED ENV{LLVM_ROOT})
list (APPEND LLVM_CONFIG_PATH_HINTS "$ENV{LLVM_ROOT}/bin")
endif ()
list (APPEND LLVM_CONFIG_PATH_HINTS
"/usr/local/opt/llvm/${LLVM_VERSION}/bin/"
@@ -121,7 +127,7 @@ endif ()
foreach (COMPONENT clangFrontend clangDriver clangSerialization
clangParse clangSema clangAnalysis clangAST clangBasic
clangEdit clangLex)
clangEdit clangLex clangSupport)
find_library ( _CLANG_${COMPONENT}_LIBRARY
NAMES ${COMPONENT}
PATHS ${LLVM_LIB_DIR})
+3 -6
View File
@@ -20,12 +20,9 @@ macro (find_python)
# Attempt to find the desired version, but fall back to other
# additional versions.
unset (_req)
if (USE_PYTHON)
set (_req REQUIRED)
if (PYTHON_VERSION)
list (APPEND _req EXACT)
endif ()
set (_req REQUIRED)
if (PYTHON_VERSION)
list (APPEND _req EXACT)
endif ()
checked_find_package (Python ${PYTHON_VERSION}
${_req}
+9 -6
View File
@@ -71,6 +71,10 @@ macro (add_one_testsuite testname testsrcdir)
set_tests_properties (${testname} PROPERTIES LABELS render
PROCESSORS 4 COST 10 TIMEOUT ${OSL_TEST_BIG_TIMEOUT})
endif ()
# For debug builds, render tests are very slow, so give them a longer timeout
if (${testname} MATCHES "render-" AND ${CMAKE_BUILD_TYPE} STREQUAL Debug)
set_tests_properties (${testname} PROPERTIES TIMEOUT ${OSL_TEST_BIG_TIMEOUT})
endif ()
# Some labeling for fun
if (${testname} MATCHES "^texture")
set_tests_properties (${testname} PROPERTIES LABELS texture
@@ -139,9 +143,6 @@ macro ( TESTSUITE )
add_one_testsuite ("${_testname}.opt" "${_testsrcdir}"
ENV TESTSHADE_OPT=2 )
endif ()
if (_testname MATCHES "render-" AND ${CMAKE_BUILD_TYPE} STREQUAL Debug)
set_tests_properties (${_testname} PROPERTIES TIMEOUT ${OSL_TEST_BIG_TIMEOUT})
endif ()
# When building for OptiX support, also run it in OptiX mode
# if there is an OPTIX marker file in the directory.
# If an environment variable $TESTSUITE_OPTIX is nonzero, then
@@ -236,7 +237,8 @@ macro (osl_add_all_tests)
bug-array-heapoffsets bug-locallifetime bug-outputinit
bug-param-duplicate bug-peep bug-return
calculatenormal-reg
cellnoise closure closure-array color color-reg colorspace comparison
cellnoise closure closure-array closure-parameters closure-zero closure-conditional
color color-reg colorspace comparison
complement-reg compile-buffer compassign-reg
component-range
control-flow-reg connect-components
@@ -322,6 +324,7 @@ macro (osl_add_all_tests)
render-mx-sheen
render-microfacet render-oren-nayar
render-uv render-veachmis render-ward
render-raytypes
select select-reg shaderglobals shortcircuit
smoothstep-reg
spline spline-reg splineinverse splineinverse-ident
@@ -351,7 +354,7 @@ macro (osl_add_all_tests)
transform transform-reg transformc transformc-reg trig trig-reg
typecast
unknown-instruction
userdata userdata-passthrough
userdata userdata-custom userdata-passthrough
vararray-connect vararray-default
vararray-deserialize vararray-param
vecctr vector vector-reg
@@ -383,7 +386,7 @@ macro (osl_add_all_tests)
endif()
# Only run pointcloud tests if Partio is found
if (PARTIO_FOUND)
if (partio_FOUND)
TESTSUITE ( pointcloud pointcloud-fold )
endif ()
+63 -34
View File
@@ -2631,27 +2631,6 @@ and proceeds to the next iteration of the loop.
\section{Functions}
\label{sec:functions}
\subsection{Function calls}
\label{sec:syntax:functioncalls}
\index{function calls}
Function calls are very similar to C and related programming languages:
\begin{tabbing}
\hspace{0.5in} \= \hspace{0.3in} \= \kill
\> \emph{functionname} {\cf (} \emph{arg1} {\cf ,} ... {\cf ,} \emph{argn} {\cf )} \\
\end{tabbing}
If the function returns a value (not \void), you may use its value as
an expression. It is fine to completely ignore the value of even
a non-\void function.
In \langname, all arguments are passed by reference. This generally
will not be noticeably different from C-style ``pass by value''
semantics, except if you pass the same variable as two separate
arguments to a function that modifies an argument's value.
\subsection{Function definitions}
\label{sec:syntax:functiondefinitions}
\index{functions!definitions}
@@ -2699,6 +2678,35 @@ 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{Function calls}
\label{sec:syntax:functioncalls}
\index{function calls}
Function calls are very similar to C and related programming languages:
\begin{tabbing}
\hspace{0.5in} \= \hspace{0.3in} \= \kill
\> \emph{functionname} {\cf (} \emph{arg1} {\cf ,} ... {\cf ,} \emph{argn} {\cf )} \\
\end{tabbing}
If the function returns a value (not \void), you may use its value as
an expression. It is fine to completely ignore the value of even
a non-\void function.
In \langname, all arguments are passed by reference. This generally
will not be noticeably different from C-style ``pass by value''
semantics, except if you pass the same variable as two separate
arguments to a function that modifies an argument's value.
Certain functions allow optional arguments to be passed.
Optional arguments are key-value pairs with the key passed as an
argument and the associated value passed as the subsequent argument:
\begin{tabbing}
\hspace{0.5in} \= \hspace{0.3in} \= \kill
\> \emph{functionname} {\cf (} \emph{arg1} {\cf ,} ... {\cf ,} \emph{argn} {\cf ,} \emph{"optionalkey"} {\cf ,} \emph{optionalvalue} {\cf ,} ... {\cf )} \\
\end{tabbing}
\subsection{Operator overloading}
\label{sec:syntax:operatoroverloading}
\index{operator overloading}
@@ -4083,8 +4091,8 @@ 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
channels.
The 2D lookup coordinate(s) may be followed by optional token/value
arguments that control the behavior of {\cf texture()}:
The 2D lookup coordinate(s) may be followed by optional key-value
arguments (see Section~\ref{sec:syntax:functioncalls}) that control the behavior of {\cf texture()}:
\apiitem{"blur", <float>}
\vspace{12pt}
@@ -5599,7 +5607,7 @@ forms of the function with no object name, or if the object name is the
empty string \qkw{}, the renderer will first search
per-object attributes on the current object (or interpolated variables
with that name attached to the object), then if not found it will search
searching global scene-wide attributes.
global scene-wide attributes.
If the attribute is found and can be converted to the type of
\emph{destination}, the attribute's value will be stored in
@@ -5901,17 +5909,38 @@ view-dependence into shaders.
The return value is 0 if the ray missed all geometry, 1 if it hit
anything within the distance range.
Optional parameters include:
The following optional key-value arguments
(see Section~\ref{sec:syntax:functioncalls}) can be passed:
\begin{tabular}{p{1.2in} p{0.5in} p{3.2in}}
\qkw{mindist} & {\cf float} & Minimum hit distance (default: zero) \\
\qkw{maxdist} & {\cf float} & Maximum hit distance (default: infinite) \\
\qkw{shade} & {\cf int} & Whether objects hit will be shaded
(default: 0) \\
\qkw{traceset} & {\cf string} & An optional named set of objects to
ray trace (if preceded by a `{\cf -}'
character, it means to exclude that set).
\end{tabular}
\apiitem{"mindist", <float>}
\vspace{12pt}
The minimum hit distance (default: 0).
The units of the {\cf "mindist"} and {\cf "maxdist"} are determined by the renderer
and are sometimes defined by the dir vector, which can lead to unexpected
behavior. So, generally, clearly written and portable shaders should pass
a unit length (see Section~\ref{sec:stdlib:geom}) dir vector.
\apiend
\vspace{-16pt}
\apiitem{"mindist", <float>}
\vspace{12pt}
The maximum hit distance (default: infinite).
\apiend
\vspace{-16pt}
\apiitem{"shade", <int>}
\vspace{12pt}
Defines whether objects hit will be shaded (default: 0).
\apiend
\vspace{-16pt}
\apiitem{"traceset", <string>}
\vspace{12pt}
An optional named set of objects to ray trace (if preceded by a `{\cf -}'
character, it means to exclude that set).
\apiend
\vspace{-16pt}
Information about the closest object hit by the ray may be retrieved
using \\ {\cf getmessage("trace",...)} (see Section~\ref{sec:getmessage}).
+14 -11
View File
@@ -6,10 +6,6 @@
#include <OSL/oslconfig.h>
#ifdef __CUDA_ARCH__
# include <optix.h>
#endif
// USAGE NOTES:
//
// To define a "standard" DeviceString, add a STRDECL to <OSL/strdecls.h>
@@ -36,20 +32,20 @@ OSL_NAMESPACE_ENTER
// stored in the table, in the 16 bytes preceding the characters.
struct DeviceString {
#ifdef __CUDA_ARCH__
#if defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000
size_t m_chars;
#else
const char* m_chars;
#endif
#ifdef __CUDA_ARCH__
#if defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000
OSL_HOSTDEVICE DeviceString() {}
OSL_HOSTDEVICE DeviceString(uint64_t i) : m_chars(i) {}
#endif
OSL_HOSTDEVICE uint64_t hash() const
{
#ifdef __CUDA_ARCH__
#if defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000
return m_chars;
#else
return *(uint64_t*)(m_chars - sizeof(uint64_t) - sizeof(uint64_t));
@@ -58,7 +54,7 @@ struct DeviceString {
// In OptiX 7 we don't store the string's length. Make this a compile
// time error.
#ifndef __CUDA_ARCH__
#if !(defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000)
OSL_HOSTDEVICE uint64_t length() const
{
return *(uint64_t*)(m_chars - sizeof(uint64_t));
@@ -67,7 +63,7 @@ struct DeviceString {
// In OptiX 7 we can't return the string's contents. Make this a compile
// time error.
#ifndef __CUDA_ARCH__
#if !(defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000)
OSL_HOSTDEVICE const char* c_str() const
{
return m_chars;
@@ -84,7 +80,7 @@ struct DeviceString {
return m_chars != other.m_chars;
}
#ifdef __CUDA_ARCH__
#if defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000
OSL_HOSTDEVICE bool operator==(const size_t other) const
{
@@ -129,6 +125,9 @@ typedef DeviceString StringParam;
namespace DeviceStrings {
# define STRDECL(str, var_name) \
extern __device__ OSL_NAMESPACE::DeviceString var_name;
# if OPTIX_VERSION < 70000
# include <OSL/strdecls.h>
# endif
# undef STRDECL
} // namespace DeviceStrings
#else
@@ -143,6 +142,10 @@ namespace DeviceStrings {
OSL_NAMESPACE_EXIT
#ifndef __CUDA_ARCH__
#ifdef __CUDA_ARCH__
# if OPTIX_VERSION < 70000
namespace StringParams = OSL_NAMESPACE::DeviceStrings;
# endif
#else
namespace StringParams = OSL_NAMESPACE::Strings;
#endif
+31 -25
View File
@@ -108,12 +108,6 @@ public:
void jit_aggressive(bool val) { m_jit_aggressive = val; }
bool jit_aggressive() const { return m_jit_aggressive; }
// Select whether the representation of a ustring is going to be
// the character pointer, or the hash.
enum class UstringRep { charptr, hash };
UstringRep ustring_rep() const { return m_ustring_rep; }
void ustring_rep(UstringRep rep);
/// Return a reference to the current context.
llvm::LLVMContext& context() const { return *m_llvm_context; }
@@ -154,6 +148,15 @@ public:
void debug_pop_inlined_function();
void debug_set_location(OIIO::ustring sourcefile, int sourceline);
/// Create a new function (that will later be populated with
/// instructions) with up to 4 args.
OSL_DEPRECATED("Use make_function flavor that takes a cspan (1.12)")
llvm::Function* make_function(const std::string& name, bool fastcall,
llvm::Type* rettype, llvm::Type* arg1 = NULL,
llvm::Type* arg2 = NULL,
llvm::Type* arg3 = NULL,
llvm::Type* arg4 = NULL);
/// Create a new function (that will later be populated with
/// instructions) with a cspan of args.
llvm::Function* make_function(const std::string& name, bool fastcall,
@@ -280,7 +283,12 @@ public:
Linkage default_linkage = Linkage::Internal,
std::string* out_err = nullptr);
OSL_DEPRECATED("prune_and_internalize_module is better (1.13)")
// OLD, might deprecate later
/// Change symbols in the module that are marked as having external
/// linkage to an alternate linkage that allows them to be discarded if
/// not used within the module. Only do this for functions that start
/// with prefix, and that DON'T match anything in the two exceptions
/// lists.
void internalize_module_functions(
const std::string& prefix, const std::vector<std::string>& exceptions,
const std::vector<std::string>& moreexceptions);
@@ -303,7 +311,7 @@ public:
/// Create a new LLVM basic block (for the current function) and return
/// its handle.
llvm::BasicBlock* new_basic_block(const std::string& name = {});
llvm::BasicBlock* new_basic_block(const std::string& name = std::string());
/// Save the return block pointer when entering a function. If
/// after==NULL, generate a new basic block for where to go after the
@@ -535,8 +543,8 @@ public:
llvm::Type* type_triple() const { return m_llvm_type_triple; }
llvm::Type* type_matrix() const { return m_llvm_type_matrix; }
llvm::Type* type_typedesc() const { return m_llvm_type_longlong; }
llvm::Type* type_ustring() { return m_llvm_type_ustring; }
llvm::PointerType* type_void_ptr() const { return m_llvm_type_void_ptr; }
llvm::PointerType* type_string() { return m_llvm_type_char_ptr; }
llvm::PointerType* type_ustring_ptr() const
{
return m_llvm_type_ustring_ptr;
@@ -571,8 +579,7 @@ public:
llvm::Type* type_wide_triple() const { return m_llvm_type_wide_triple; }
llvm::Type* type_wide_matrix() const { return m_llvm_type_wide_matrix; }
llvm::Type* type_wide_void_ptr() const { return m_llvm_type_wide_void_ptr; }
llvm::Type* type_wide_ustring() const { return m_llvm_type_wide_ustring; }
llvm::PointerType* type_wide_ustring_ptr() const
llvm::Type* type_wide_string() const
{
return m_llvm_type_wide_ustring_ptr;
}
@@ -622,7 +629,7 @@ public:
bool is_packed = false);
/// Return the llvm::Type that is a pointer to the given llvm type.
llvm::PointerType* type_ptr(llvm::Type* type);
llvm::Type* type_ptr(llvm::Type* type);
/// Return the llvm::Type that is the wide version of the given llvm type
llvm::Type* type_wide(llvm::Type* type);
@@ -631,6 +638,12 @@ public:
/// llvm type.
llvm::Type* type_array(llvm::Type* type, int n);
/// Return the true if the llvm::Type is an array
bool is_type_array(llvm::Type* type);
/// Return the llvm::Type of element that the array_type is made up of
llvm::Type* element_type_of(llvm::Type* array_type);
/// Return an llvm::FunctionType that describes a function with the
/// given return types, parameter types (in a cspan), and whether it
/// uses varargs conventions.
@@ -680,8 +693,7 @@ public:
/// If the type specified is NULL, it will make a 'void *'.
llvm::Value* constant_ptr(void* p, llvm::PointerType* type = NULL);
/// Return an llvm::Value holding the given string constant (as
/// determined by the ustring_rep).
/// Return an llvm::Value holding the given string constant.
llvm::Value* constant(ustring s);
llvm::Value* constant(string_view s) { return constant(ustring(s)); }
@@ -1014,10 +1026,9 @@ private:
IRBuilder& builder();
int m_debug;
bool m_dumpasm = false;
bool m_jit_fma = false;
bool m_jit_aggressive = false;
UstringRep m_ustring_rep = UstringRep::charptr;
bool m_dumpasm = false;
bool m_jit_fma = false;
bool m_jit_aggressive = false;
PerThreadInfo::Impl* m_thread;
llvm::LLVMContext* m_llvm_context;
llvm::Module* m_llvm_module;
@@ -1033,9 +1044,6 @@ private:
std::vector<llvm::BasicBlock*> m_loop_after_block; // stack for break
std::vector<llvm::BasicBlock*> m_loop_step_block; // stack for continue
// Incrementing serial numbers
int m_next_serial_bb = 0;
llvm::Type* m_llvm_type_float;
llvm::Type* m_llvm_type_double;
llvm::Type* m_llvm_type_int;
@@ -1048,8 +1056,8 @@ private:
llvm::Type* m_llvm_type_void;
llvm::Type* m_llvm_type_triple;
llvm::Type* m_llvm_type_matrix;
llvm::Type* m_llvm_type_ustring;
llvm::PointerType* m_llvm_type_void_ptr;
llvm::PointerType* m_llvm_type_ustring_ptr;
llvm::PointerType* m_llvm_type_char_ptr;
llvm::PointerType* m_llvm_type_bool_ptr;
llvm::PointerType* m_llvm_type_int_ptr;
@@ -1058,7 +1066,6 @@ private:
llvm::PointerType* m_llvm_type_triple_ptr;
llvm::PointerType* m_llvm_type_matrix_ptr;
llvm::PointerType* m_llvm_type_double_ptr;
llvm::PointerType* m_llvm_type_ustring_ptr;
int m_vector_width;
llvm::Type* m_llvm_type_wide_float;
@@ -1070,12 +1077,11 @@ private:
llvm::Type* m_llvm_type_wide_triple;
llvm::Type* m_llvm_type_wide_matrix;
llvm::Type* m_llvm_type_wide_void_ptr;
llvm::Type* m_llvm_type_wide_ustring;
llvm::Type* m_llvm_type_wide_ustring_ptr;
llvm::PointerType* m_llvm_type_wide_char_ptr;
llvm::PointerType* m_llvm_type_wide_int_ptr;
llvm::PointerType* m_llvm_type_wide_bool_ptr;
llvm::PointerType* m_llvm_type_wide_float_ptr;
llvm::PointerType* m_llvm_type_wide_ustring_ptr;
llvm::Type* m_llvm_type_native_mask;
bool m_supports_masked_stores = false;
+1 -28
View File
@@ -102,7 +102,7 @@ using OIIO::TextureOpt;
// And some other things we borrow from OIIO...
using OIIO::ErrorHandler;
using OIIO::ustring;
using OIIO::ustringhash;
using OIIO::ustringHash;
using OIIO::string_view;
using OIIO::span;
using OIIO::cspan;
@@ -225,30 +225,3 @@ using ConstIndex = std::integral_constant<int, N>;
OSL_NAMESPACE_EXIT
namespace std { // not necessary in C++17, then we can just say std::hash
#ifndef OIIO_USTRING_HAS_STDHASH
// Not a new enough OIIO to define std::hash<ustring>, so we'll do it
template<> struct hash<OSL::ustring> {
std::size_t operator()(OSL::ustring u) const noexcept { return u.hash(); }
};
template<> struct hash<OSL::ustringhash> {
OSL_HOSTDEVICE constexpr std::size_t
operator()(OSL::ustringhash u) const noexcept
{
return u.hash();
}
};
#endif
// Not necessary once minimum OIIO defines operator< for ustringhash
template<> struct less<OSL::ustringhash> {
OSL_HOSTDEVICE constexpr bool operator()(OSL::ustringhash u,
OSL::ustringhash v) const noexcept
{
return u.hash() < v.hash();
}
};
} // namespace std
+14 -14
View File
@@ -50,7 +50,7 @@ namespace pvt {
class ShadingSystemImpl;
}
#ifdef __CUDA_ARCH__
#if defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000
# define STRING_PARAMS(x) UStringHash::Hash(__OSL_STRINGIFY(x))
#else
# define STRING_PARAMS(x) StringParams::x
@@ -58,7 +58,11 @@ class ShadingSystemImpl;
namespace Strings {
#ifdef __CUDA_ARCH__
# define STRDECL(str, var_name)
# if OPTIX_VERSION >= 70000
# define STRDECL(str, var_name)
# else
# define STRDECL(str, var_name) extern __device__ const ustring var_name;
# endif
#else
// Any strings referenced inside of a libsoslexec/wide/*.cpp
// or liboslnoise/wide/*.cpp will need OSLEXECPUBLIC
@@ -231,7 +235,8 @@ public:
/// for debugging. (0)
/// int llvm_dumpasm Print the CPU assembly code from the JIT (0)
/// string llvm_prune_ir_strategy Strategy for pruning unnecessary
/// IR (choices: "prune" [default], or "none").
/// IR (choices: "prune" [default],
/// "internalize", or "none").
/// 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
@@ -427,12 +432,15 @@ public:
/// ptr attributes_needed Retrieves a pointer to the ustring array
/// containing the names of the needed attributes.
/// Note that if the same attribute
/// is requested in multiple scopes, it will
/// is requested in multiple scopes, or with
/// multiple different types, it will
/// appear in the array multiple times - once for
/// each scope in which is is queried.
/// each scope/type in which is is queried.
/// ptr attribute_scopes Retrieves a pointer to a ustring array containing
/// the scopes associated with each attribute query
/// in the attributes_needed array.
/// ptr attribute_types Retrieves a pointer to the array of
/// TypeDesc describing the attributes.
/// int unknown_attributes_needed Nonzero if additional attributes may be
/// needed, whose names will not be known
/// until the shader actually runs.
@@ -443,6 +451,7 @@ public:
/// string entry_layers[] List of entry point layers.
/// string pickle Retrieves a serialized representation
/// of the shader group declaration.
/// int llvm_groupdata_size Size of the GroupData struct.
/// Note: the attributes referred to as "string" are actually on the app
/// side as ustring or const char* (they have the same data layout), NOT
/// std::string!
@@ -672,15 +681,6 @@ public:
ShaderGlobals& globals, void* userdata_base_ptr,
void* output_base_ptr, bool run = true);
/// Future execute signature that will be range based. Shader globals will be
/// obtained from renderer services.
#if 0 // TODO in future PR
bool execute(ShadingContext& ctx, ShaderGroup& group, OpaqueShadingStateUniformPtr ssu,
int shadeindex_begin_at, int shadeindex_end_before
void* userdata_base_ptr,
void* output_base_ptr, bool run = true);
#endif
// DEPRECATED(2.0): no shadeindex or base pointers
bool execute(ShadingContext& ctx, ShaderGroup& group,
ShaderGlobals& globals, bool run = true)
+291 -291
View File
File diff suppressed because it is too large Load Diff
+19
View File
@@ -18,6 +18,7 @@
#pragma once
#include <cstring>
#include <memory>
#include <OSL/oslversion.h>
@@ -499,6 +500,24 @@
OSL_NAMESPACE_ENTER
/// Standards-compliant bit cast of two equally sized types. This is used
/// equivalently to C++20 std::bit_cast, but it works prior to C++20 and
/// it has the right decorators to work with Cuda.
/// @version 1.13.2
template <typename To, typename From>
OSL_FORCEINLINE OSL_HOSTDEVICE To bitcast(const From& src) noexcept {
// NOTE: this is the only standards compliant way of doing this type of casting,
// luckily the compilers we care about know how to optimize away this idiom.
static_assert(sizeof(From) == sizeof(To),
"bit_cast must be between objects of the same size");
To dst;
memcpy((void*)&dst, &src, sizeof(From));
return dst;
}
#if OSL_CPLUSPLUS_VERSION >= 20
using std::assume_aligned;
#else
+9
View File
@@ -405,6 +405,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;
}
virtual uint64_t register_global (const std::string& var_name,
uint64_t value)
{
-4
View File
@@ -17,9 +17,6 @@ class RendererServices;
/// coordinate transformation.
typedef const void* TransformationPtr;
/// Type for an opaque pointer to whatever the Shading System uses to represent
/// Uniform State.
typedef const void* OpaqueShadingStateUniformPtr;
/// The ShaderGlobals structure represents the state describing a particular
@@ -86,7 +83,6 @@ struct ShaderGlobals {
/// Back-pointer to the ShadingContext (set and used by OSL itself --
/// renderers shouldn't mess with this at all).
ShadingContext* context;
OpaqueShadingStateUniformPtr shadingStateUniform;
/// Pointer to the RendererServices object. This is how OSL finds its
/// way back to the renderer for callbacks.
+35 -9
View File
@@ -2845,7 +2845,7 @@ public:
// Populate all data lanes of the MaskedData by broadcasting the
// single instance of data pointed to.
// Masked off lanes are not overwritten.
// Includes value, as well as Dx and Dy when has_derivs() is true
// when has_derivs() is true, Dx and Dy will be zeroed
OSL_FORCEINLINE void assign_all_from_scalar(const void* ptr_data) const;
@@ -2863,6 +2863,9 @@ private:
template<typename DataT>
OSL_NOINLINE void assign_all_from_scalar_type(const void* ptr_data,
int deriv_index) const;
template<typename DataT>
OSL_NOINLINE void zero_all_type(int deriv_index) const;
};
@@ -3378,6 +3381,33 @@ MaskedData<WidthT>::assign_all_from_scalar_type(const void* ptr_data,
}
}
template<int WidthT>
template<typename DataT>
OSL_NOINLINE void
MaskedData<WidthT>::zero_all_type(int deriv_index) const
{
// We can't just do a memset because some lanes may be masked off
// Use a SIMD loop to perform masked assignment.
auto* dst_blocks = pvt::block_cast<DataT, WidthT>(m_ptr);
int elem_count = static_cast<int>(m_type.numelements());
int comp_count = m_type.aggregate;
int deriv_offset = deriv_index * elem_count * comp_count;
for (int array_index = 0; array_index < elem_count; ++array_index) {
int array_offset = array_index * comp_count;
for (int comp_index = 0; comp_index < comp_count; ++comp_index) {
int combined_index = deriv_offset + array_offset + comp_index;
auto& bdst = dst_blocks[combined_index];
Masked<DataT, WidthT> wdest(bdst, mask());
OSL_OMP_PRAGMA(omp simd simdlen(WidthT))
for (int lane = 0; lane < WidthT; ++lane) {
wdest[lane] = DataT {};
}
}
}
}
template<int WidthT>
OSL_FORCEINLINE void
MaskedData<WidthT>::assign_all_from_scalar(const void* ptr_data) const
@@ -3393,16 +3423,12 @@ MaskedData<WidthT>::assign_all_from_scalar(const void* ptr_data) const
assign_all_from_scalar_type<ustring>(ptr_data, /*deriv_index*/ 0);
}
if (has_derivs()) {
size_t src_size = type().size();
const char* dx_src = reinterpret_cast<const char*>(ptr_data) + src_size;
const char* dy_src = dx_src + src_size;
if (isBase32bit) {
assign_all_from_scalar_type<int>(dx_src, /*deriv_index*/ 1);
assign_all_from_scalar_type<int>(dy_src, /*deriv_index*/ 2);
zero_all_type<int>(/*deriv_index*/ 1);
zero_all_type<int>(/*deriv_index*/ 2);
} else {
assign_all_from_scalar_type<ustring>(dx_src, /*deriv_index*/ 1);
assign_all_from_scalar_type<ustring>(dy_src, /*deriv_index*/ 2);
zero_all_type<ustring>(/*deriv_index*/ 1);
zero_all_type<ustring>(/*deriv_index*/ 2);
}
}
}
+8 -17
View File
@@ -5,7 +5,6 @@
#pragma once
#include <OSL/oslconfig.h>
#include <OSL/oslversion.h>
#ifdef OSL_USE_OPTIX
@@ -14,18 +13,14 @@
# ifdef _WIN32
# define NOMINMAX
# endif
# if (OPTIX_VERSION < 70000)
# include <optix_world.h>
# endif
#else
# include <stdlib.h>
#endif
#if !defined(OSL_USE_OPTIX) && !defined(__CUDA_ARCH__)
using CUdeviceptr = void*;
using float3 = OSL::Vec3;
#endif
OSL_NAMESPACE_ENTER
#ifdef OSL_USE_OPTIX
@@ -36,12 +31,14 @@ OSL_NAMESPACE_ENTER
// TODO clean this up once OptiX6 support is dropped
# if (OPTIX_VERSION < 70000)
namespace optix = ::optix;
# else
namespace optix {
typedef OptixDeviceContext Context;
typedef cudaTextureObject_t TextureSampler;
using ::CUdeviceptr;
using ::float3;
} // namespace optix
# endif
using ::cudaFree;
using ::cudaMalloc;
@@ -52,19 +49,13 @@ using ::cudaMalloc;
////////////////////////////////////////////////////////////////////////
// If OptiX is not available, make reasonable proxies just so that we
// don't have to litter the code with quite as many #ifdef's.
// Mostly under OSL::optix::
// OSL::optix::
namespace optix {
typedef void* Context;
typedef void* Program;
typedef void* TextureSampler;
typedef void* CUdeviceptr;
using float3 = OSL::Vec3;
struct Exception {
static const char* what() { return "OSL compiled without Optix."; }
};
+11
View File
@@ -386,6 +386,7 @@ public:
/// vector-like (and match their array-ness and closure-ness), or
/// if both are structures with matching fields.
friend bool equivalent(const TypeSpec& a, const TypeSpec& b);
friend bool relaxed_equivalent(const TypeSpec& a, const TypeSpec& b);
/// Is type src is assignable to dst? It is if they are the equivalent(),
/// or if dst is a float or float-aggregate and src is a float or int.
@@ -1285,3 +1286,13 @@ typedef std::vector<Opcode> OpcodeVec;
}; // namespace pvt
OSL_NAMESPACE_EXIT
// Supply a fmtlib compatible custom formatter for TypeSpec.
#if FMT_VERSION >= 100000
FMT_BEGIN_NAMESPACE
template<> struct formatter<OSL::pvt::TypeSpec> : ostream_formatter {
};
FMT_END_NAMESPACE
#endif
+34 -36
View File
@@ -1116,90 +1116,88 @@ ASTassign_expression::opword() const
OSL_ASSERT (0 && "unknown assignment expression");
return "assign"; // punt
}
// clang-format on
}
ASTunary_expression::ASTunary_expression (OSLCompilerImpl *comp, int op,
ASTNode *expr)
: ASTNode (unary_expression_node, comp, op, expr)
ASTunary_expression::ASTunary_expression(OSLCompilerImpl* comp, int op,
ASTNode* expr)
: ASTNode(unary_expression_node, comp, op, expr)
{
// Check for a user-overloaded function for this operator
Symbol *sym = comp->symtab().find(ustring::fmtformat("__operator__{}__", opword()));
Symbol* sym = comp->symtab().find(
ustring::fmtformat("__operator__{}__", opword()));
if (sym && sym->symtype() == SymTypeFunction)
m_function_overload = (FunctionSymbol *)sym;
m_function_overload = (FunctionSymbol*)sym;
}
const char *
ASTunary_expression::childname (size_t i) const
const char*
ASTunary_expression::childname(size_t i) const
{
static const char *name[] = { "expression" };
static const char* name[] = { "expression" };
return name[i];
}
const char *
ASTunary_expression::opname () const
const char*
ASTunary_expression::opname() const
{
switch (m_op) {
case Add : return "+";
case Sub : return "-";
case Not : return "!";
case Compl : return "~";
default:
OSL_ASSERT (0 && "unknown unary expression");
return "unknown";
case Add: return "+";
case Sub: return "-";
case Not: return "!";
case Compl: return "~";
default: OSL_ASSERT(0 && "unknown unary expression"); return "unknown";
}
}
const char *
ASTunary_expression::opword () const
const char*
ASTunary_expression::opword() const
{
switch (m_op) {
case Add : return "add";
case Sub : return "neg";
case Not : return "not";
case Compl : return "compl";
default:
OSL_ASSERT (0 && "unknown unary expression");
return "unknown";
case Add: return "add";
case Sub: return "neg";
case Not: return "not";
case Compl: return "compl";
default: OSL_ASSERT(0 && "unknown unary expression"); return "unknown";
}
}
ASTbinary_expression::ASTbinary_expression (OSLCompilerImpl *comp, Operator op,
ASTNode *left, ASTNode *right)
: ASTNode (binary_expression_node, comp, op, left, right)
ASTbinary_expression::ASTbinary_expression(OSLCompilerImpl* comp, Operator op,
ASTNode* left, ASTNode* right)
: ASTNode(binary_expression_node, comp, op, left, right)
{
// Check for a user-overloaded function for this operator.
// Disallow a few ops from overloading.
if (op != And && op != Or) {
ustring funcname = ustring::fmtformat("__operator__{}__", opword());
Symbol *sym = comp->symtab().find (funcname);
Symbol* sym = comp->symtab().find(funcname);
if (sym && sym->symtype() == SymTypeFunction)
m_function_overload = (FunctionSymbol *)sym;
m_function_overload = (FunctionSymbol*)sym;
}
}
const char *
ASTbinary_expression::childname (size_t i) const
const char*
ASTbinary_expression::childname(size_t i) const
{
static const char *name[] = { "left", "right" };
static const char* name[] = { "left", "right" };
return name[i];
}
const char *
ASTbinary_expression::opname () const
const char*
ASTbinary_expression::opname() const
{
// clang-format off
switch (m_op) {
+3 -2
View File
@@ -701,11 +701,12 @@ OSLCompilerImpl::write_oso_const_value(const ConstantSymbol* sym) const
osofmt("{}{}", sym->get_int(i), nelements > 1 ? " " : "");
else if (elemtype == TypeDesc::FLOAT)
for (int i = 0; i < nelements; ++i)
osofmt("{}{}", sym->floatval(i), nelements > 1 ? " " : "");
osofmt("{:.9g}{}", sym->floatval(i), nelements > 1 ? " " : "");
else if (equivalent(elemtype, TypeDesc::TypeVector))
for (int i = 0; i < nelements; ++i) {
Vec3 v = sym->get_vec3(i);
osofmt("{} {} {}{}", v.x, v.y, v.z, nelements > 1 ? " " : "");
osofmt("{:.9g} {:.9g} {:.9g}{}", v.x, v.y, v.z,
nelements > 1 ? " " : "");
}
else {
OSL_ASSERT(0 && "Don't know how to output this constant type");
+1 -1
View File
@@ -490,7 +490,7 @@ private:
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> FCMap;
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
-12
View File
@@ -397,15 +397,6 @@ OSLCompilerImpl::osl_parse_buffer (const std::string &preprocessed_buffer)
// Thread safety with the lexer/parser
std::lock_guard<std::mutex> lock(oslcompiler_mutex);
#ifndef OIIO_STRUTIL_HAS_STOF
// Force classic "C" locale for correct '.' decimal parsing.
// N.B. This is not safe in a multi-threaded program where another
// application thread is expecting the native locale to work properly.
// This is not necessary for versions of OIIO that have Strutil::stof,
// and we can remove it entirely when OIIO 1.9 is the minimum.
std::locale oldlocale = std::locale::global (std::locale::classic());
#endif
yyscan_t scanner;
yylex_init(&scanner);
YY_BUFFER_STATE buffer = yy_scan_string(preprocessed_buffer.c_str(), scanner);
@@ -415,9 +406,6 @@ OSLCompilerImpl::osl_parse_buffer (const std::string &preprocessed_buffer)
yy_delete_buffer (buffer, scanner);
yylex_destroy(scanner);
#ifndef OIIO_STRUTIL_HAS_STOF
std::locale::global (oldlocale); // Restore the original locale.
#endif
return parseerr;
}
+1 -1
View File
@@ -186,7 +186,7 @@ private:
///
class SymbolTable {
public:
typedef std::unordered_map<ustring, Symbol*> ScopeTable;
typedef std::unordered_map<ustring, Symbol*, ustringHash> ScopeTable;
typedef std::vector<ScopeTable> ScopeTableStack;
typedef SymbolPtrVec::iterator iterator;
typedef SymbolPtrVec::const_iterator const_iterator;
+3 -3
View File
@@ -23,12 +23,12 @@ OSL_NAMESPACE_ENTER
typedef std::set<int>
IntSet; // probably faster to test for equality, unions and so
typedef std::unordered_set<ustring> SymbolSet;
typedef std::unordered_set<ustring, ustringHash> SymbolSet;
// This is for the transition table used in DfAutomata::State
typedef std::unordered_map<ustring, int> SymbolToInt;
typedef std::unordered_map<ustring, int, ustringHash> SymbolToInt;
// And this is for the transition table in NdfAutomata which
// has several movements for each symbol
typedef std::unordered_map<ustring, IntSet> SymbolToIntList;
typedef std::unordered_map<ustring, IntSet, ustringHash> SymbolToIntList;
typedef std::unordered_map<int, int> HashIntInt;
// For the rules in the deterministic states, we don't need a real set
+244 -77
View File
@@ -6,10 +6,6 @@
#include <OpenImageIO/filesystem.h>
#include <OpenImageIO/strutil.h>
#ifdef OSL_USE_OPTIX
# include <optix.h>
#endif
#include "oslexec_pvt.h"
#include "backendllvm.h"
@@ -87,12 +83,6 @@ BackendLLVM::BackendLLVM(ShadingSystemImpl& shadingsys, ShaderGroup& group,
#endif
m_use_optix = shadingsys.renderer()->supports("OptiX");
m_use_rs_bitcode = !shadingsys.m_rs_bitcode.empty();
m_name_llvm_syms = shadingsys.m_llvm_output_bitcode;
// Select the appropriate ustring representation
ll.ustring_rep(m_use_optix ? LLVM_Util::UstringRep::hash
: LLVM_Util::UstringRep::charptr);
ll.dumpasm(shadingsys.m_llvm_dumpasm);
ll.jit_fma(shadingsys.m_llvm_jit_fma);
ll.jit_aggressive(shadingsys.m_llvm_jit_aggressive);
@@ -141,7 +131,7 @@ BackendLLVM::llvm_pass_type(const TypeSpec& typespec)
else if (t == TypeDesc::INT)
lt = ll.type_int();
else if (t == TypeDesc::STRING)
lt = (llvm::Type*)ll.type_ustring();
lt = (llvm::Type*)ll.type_string();
else if (t.aggregate == TypeDesc::VEC3)
lt = (llvm::Type*)ll.type_void_ptr(); //llvm_type_triple_ptr();
else if (t.aggregate == TypeDesc::MATRIX44)
@@ -236,7 +226,6 @@ static ustring fields[] = { ustring("P"),
ustring("tracedata"),
ustring("objdata"),
ustring("shadingcontext"),
ustring("shadingStateUniform"),
ustring("renderer"),
ustring("object2common"),
ustring("shader2common"),
@@ -267,7 +256,7 @@ BackendLLVM::llvm_global_symbol_ptr(ustring name)
int sg_index = ShaderGlobalNameToIndex(name);
OSL_ASSERT(sg_index >= 0);
return ll.void_ptr(ll.GEP(sg_ptr(), 0, sg_index),
llnamefmt("glob_{}_voidptr", name));
fmtformat("glob_{}_voidptr", name));
}
@@ -330,7 +319,7 @@ BackendLLVM::getOrAllocateLLVMSymbol(const Symbol& sym)
if (map_iter == named_values().end()) {
llvm::Value* a = llvm_alloca(sym.typespec(), sym.has_derivs(),
llnamefmt("{}_mem", mangled_name));
mangled_name);
named_values()[mangled_name] = a;
return a;
}
@@ -340,9 +329,8 @@ BackendLLVM::getOrAllocateLLVMSymbol(const Symbol& sym)
llvm::Value*
BackendLLVM::addCUDAGlobalVariable(const std::string& name, int size,
int alignment, const void* init_data,
TypeDesc type)
BackendLLVM::addCUDAVariable(const std::string& name, int size, int alignment,
const void* data, TypeDesc type)
{
OSL_ASSERT(use_optix()
&& "This function is only supposed to be used with OptiX!");
@@ -350,16 +338,40 @@ BackendLLVM::addCUDAGlobalVariable(const std::string& name, int size,
llvm::Constant* constant = nullptr;
if (type == TypeDesc::TypeFloat) {
constant = ll.constant(*(const float*)init_data);
constant = llvm::ConstantFP::get(llvm::Type::getFloatTy(
ll.module()->getContext()),
*(float*)data);
} else if (type == TypeDesc::TypeInt) {
constant = ll.constant(*(const int*)init_data);
constant = llvm::ConstantInt::get(llvm::Type::getInt32Ty(
ll.module()->getContext()),
*(int*)data);
} else if (type == TypeDesc::TypeString) {
constant = ll.constant(((const ustring*)init_data)->hash());
// N.B. Since this is the OptiX side specifically, we will represent
// strings as the ustringhash, so we know it as a constant.
// 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);
#if OPTIX_VERSION < 70000
// 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
// DeviceStrings use the ustring hash to identify themselves. These hashes will
// match on both the device and host side.
constant = llvm::ConstantInt::get(llvm::Type::getInt64Ty(
ll.module()->getContext()),
((ustring*)data)->hash());
m_varname_map[name] = ((ustring*)data)->string();
#endif
} else {
// Handle unspecified types as generic byte arrays
llvm::ArrayRef<uint8_t> arr_ref((uint8_t*)init_data, size);
llvm::ArrayRef<uint8_t> arr_ref((uint8_t*)data, size);
constant = llvm::ConstantDataArray::get(ll.module()->getContext(),
arr_ref);
}
@@ -375,7 +387,9 @@ BackendLLVM::addCUDAGlobalVariable(const std::string& name, int size,
g_var->setAlignment(alignment);
#endif
g_var->setLinkage(llvm::GlobalValue::PrivateLinkage);
#if (OPTIX_VERSION < 70000)
g_var->setLinkage(llvm::GlobalValue::ExternalLinkage);
#endif
g_var->setVisibility(llvm::GlobalValue::DefaultVisibility);
g_var->setInitializer(constant);
m_const_map[name] = g_var;
@@ -385,32 +399,155 @@ BackendLLVM::addCUDAGlobalVariable(const std::string& name, int size,
void
BackendLLVM::createOptixMetadata(const std::string& name, const Symbol& sym)
{
// 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.
OSL_ASSERT(use_optix()
&& "This function is only supported when using OptiX!");
auto mangle_name = [](const std::string& name, const std::string& prefix) {
return fmtformat("_ZN{}rti_internal_{}{}{}E", prefix.size() + 13,
prefix, name.size(), name);
};
std::string optix_type;
const TypeDesc type = sym.typespec().simpletype();
if (!sym.typespec().is_array()) {
optix_type =
// Documented built-in types
(type == TypeDesc::TypeInt) ? "int"
: (type == TypeDesc::TypeFloat) ? "float"
: (type == TypeDesc::TypePoint) ? "float3"
: (type == TypeDesc::TypeVector) ? "float3"
: (type == TypeDesc::TypeNormal) ? "float3"
: (type == TypeDesc::TypeColor) ? "float3"
: (type == TypeDesc::TypeMatrix) ? "matrix"
: (type == TypeDesc::TypeString)
? "uint64_t"
:
// Catch-all for types that fall through, if there are any.
type.c_str();
// NB: TypeMatrix is assumed to be 4x4 and will be treated by OptiX as a
// user datatype (i.e., a generic struct).
} else {
// OptiX should handle int and float vectors between 2 and 4 dimensions
// with no problem. Larger arrays, or arrays of other element types,
// will be treated as a user datatype and will not work natively with
// OptiX's variable mechanism.
optix_type = fmtformat("{}{}", sym.typespec().elementtype(),
sym.typespec().arraylength());
}
struct rti_typeinfo {
unsigned int kind = 0x796152; // _OPTIX_VARIABLE
unsigned int size;
} type_info;
type_info.size = sym.size();
int type_enum = 0x1337; // _OPTIX_TYPE_ENUM_UNKNOWN
char zero = 0;
addCUDAVariable(mangle_name(name, "typeinfo"), 8, 4, &type_info);
addCUDAVariable(mangle_name(name, "typename"), optix_type.size() + 1, 16,
optix_type.data());
addCUDAVariable(mangle_name(name, "typeenum"), 4, 4, &type_enum,
TypeDesc::TypeInt);
addCUDAVariable(mangle_name(name, "semantic"), 1, 1, &zero);
addCUDAVariable(mangle_name(name, "annotation"), 1, 1, &zero);
}
llvm::Value*
BackendLLVM::getOrAllocateCUDAVariable(const Symbol& sym)
BackendLLVM::getOrAllocateCUDAVariable(const Symbol& sym, bool addMetadata)
{
OSL_ASSERT(use_optix()
&& "This function is only supported when using OptiX!");
// We need to sanitize the symbol name for PTX compatibility. Also, if the
// sym name starts with a dollar sign, which are not allowed in PTX
// variable names, then prepend another underscore.
std::string sym_name = Strutil::replace(sym.name(), ".", "_", true);
std::ostringstream ss;
ss.imbue(std::locale::classic()); // force C locale
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 still
// 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.
std::string name
= fmtformat("{}{}_{}_{}_{}", sym_name.front() == '$' ? "_" : "",
sym_name, group().name(), inst()->layername(), sym.layer());
ss << "ds_"
#if OPTIX_VERSION >= 70000
<< group().name() << "_" << group().id() << "_"
#endif
<< std::setbase(16) << std::setfill('0') << std::setw(16)
<< sym.get_string().hash() << "_" << std::setbase(16)
<< std::setfill('0') << std::setw(4) << sym.get_string().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 != sym.get_string().string()) {
std::cerr << "Warning: variable name collision between " << old_str
<< " and " << sym.get_string() << std::endl;
}
} else {
// We need to sanitize the symbol name for PTX compatibility
std::string sym_name = sym.name().c_str();
std::replace(sym_name.begin(), sym_name.end(), '.', '_');
std::string var_name = fmtformat("{}_{}_{}_{}_{}", sym_name,
group().name(), group().id(),
inst()->layername(), sym.layer());
// Leading dollar signs are not allowed in PTX variable names,
// so prepend an underscore.
if (var_name[0] == '$') {
ss << '_';
}
ss << var_name;
}
const std::string name = ss.str();
// Return the Value if it has already been allocated
auto it = get_const_map().find(name);
if (it != get_const_map().end())
std::map<std::string, llvm::GlobalVariable*>::iterator it
= get_const_map().find(name);
if (it != get_const_map().end()) {
return it->second;
}
#if (OPTIX_VERSION < 70000)
// Add the extra metadata needed to make the variable visible to OptiX.
if (addMetadata || sym.typespec().is_string())
createOptixMetadata(name, sym);
#endif
// TODO: Figure out the actual CUDA alignment requirements for the various
// OSL types. For now, be somewhat conservative and assume 8 for
// non-scalar types.
int alignment = (sym.typespec().is_scalarnum()) ? 4 : 8;
return addCUDAGlobalVariable(name, sym.size(), alignment, sym.data(),
sym.typespec().simpletype());
llvm::Value* cuda_var = addCUDAVariable(name, sym.size(), alignment,
sym.data(),
sym.typespec().simpletype());
return cuda_var;
}
@@ -428,37 +565,38 @@ BackendLLVM::llvm_get_pointer(const Symbol& sym, int deriv,
llvm::Value* result = NULL;
if (sym.symtype() == SymTypeConst) {
TypeSpec elemtype = 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) {
result = llvm_ptr_cast(ptr, llvm_typedesc(elemtype),
llnamefmt("cast_to_{}_", sym.typespec()));
// N.B. llvm_typedesc() for a string will know that on OptiX,
// strings are actually represented as just the hash.
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 on the CPU side, start with *OUR* pointer to the
// constant values.
result = ll.constant_ptr(sym.data(),
ll.type_ptr(llvm_type(elemtype)));
// 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 {
// If the symbol is not a SymTypeConst, then start with the initial
// pointer to the variable's memory location.
// Start with the initial pointer to the variable's memory location
result = getLLVMSymbolBase(sym);
}
if (!result)
return NULL; // Error
// If it's an array or we're dealing with derivatives, step to the right
// element.
// If it's an array or we're dealing with derivatives, step to the
// right element.
TypeDesc t = sym.typespec().simpletype();
if (t.arraylen || has_derivs) {
int d = deriv * std::max(1, t.arraylen);
if (arrayindex && d)
if (arrayindex)
arrayindex = ll.op_add(arrayindex, ll.constant(d));
else
arrayindex = ll.constant(d);
@@ -504,14 +642,13 @@ BackendLLVM::llvm_load_value(const Symbol& sym, int deriv,
return ll.constant(sym.get_float(component));
}
if (sym.typespec().is_string()) {
return llvm_load_string(sym.get_string());
return ll.constant(sym.get_string());
}
OSL_ASSERT(0 && "unhandled constant type");
}
return llvm_load_value(llvm_get_pointer(sym), sym.typespec(), deriv,
arrayindex, component, cast,
llnamefmt("{}_", sym.name()));
arrayindex, component, cast, sym.name().string());
}
@@ -551,24 +688,50 @@ BackendLLVM::llvm_load_value(llvm::Value* ptr, const TypeSpec& type, int deriv,
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::LONGLONG) {
else if (type.is_string() && cast == TypeDesc::LONGLONG)
result = ll.ptr_to_cast(result, ll.type_longlong());
// FIXME -- is this case ever used? Seems strange.
}
// We still disguise hashed strings as char*. Ideally, we would only do
// that if the rep were a charptr, but we disguise the hashes as char*'s
// also to avoid ugliness with function signatures differing between CPU
// and GPU. Maybe some day we'll use the hash representation on both
// sides?
if (type.is_string() && ll.ustring_rep() != LLVM_Util::UstringRep::charptr)
result = ll.int_to_ptr_cast(result);
return result;
}
llvm::Value*
BackendLLVM::llvm_load_device_string(const Symbol& sym, bool follow)
{
// TODO: need to make this work with arrays of strings
OSL_ASSERT(use_optix() && "This is only intended to be used with CUDA");
// Recover the userdata index for non-constant parameters
int userdata_index = find_userdata_index(sym);
llvm::Value* val = NULL;
if (sym.symtype() == SymTypeLocal || sym.symtype() == SymTypeTemp) {
// Handle temporary and local variables
val = getOrAllocateLLVMSymbol(sym);
val = ll.ptr_cast(val, ll.type_longlong_ptr());
} else if (userdata_index < 0) {
// Handle non-varying variables
OSL_DASSERT(sym.data() && "NULL data in non-varying string");
val = getOrAllocateCUDAVariable(sym);
} else {
// Handle potentially varying variables
val = ll.ptr_cast(groupdata_field_ptr(2 + userdata_index),
ll.type_longlong_ptr());
}
// It's preferable to deal with device strings "symbolically" through the
// CUDA variable (essentially a char**), which helps keep the code
// portable. But sometimes it's necessary to handle the underlying char*
// directly, e.g. when printing or writing out a closure param.
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, TypeDesc cast)
@@ -598,8 +761,13 @@ BackendLLVM::llvm_load_constant_value(const Symbol& sym, int arrayindex,
int ncomps = (int)sym.typespec().aggregate();
return ll.constant(sym.get_float(ncomps * arrayindex + component));
}
if (sym.typespec().is_string() && use_optix()) {
OSL_DASSERT((arrayindex == 0)
&& "String arrays are not currently supported in OptiX");
return llvm_load_device_string(sym, /*follow*/ false);
}
if (sym.typespec().is_string()) {
return llvm_load_string(sym.get_string(arrayindex));
return ll.constant(sym.get_string(arrayindex));
}
OSL_ASSERT(0 && "unhandled constant type");
@@ -749,20 +917,16 @@ BackendLLVM::llvm_store_component_value(llvm::Value* new_val, const Symbol& sym,
llvm::Value*
BackendLLVM::groupdata_field_ref(int fieldnum)
{
return ll.GEP(groupdata_ptr(), 0, fieldnum,
llnamefmt("{}_ref", m_groupdata_field_names[fieldnum]));
return ll.GEP(groupdata_ptr(), 0, fieldnum);
}
llvm::Value*
BackendLLVM::groupdata_field_ptr(int fieldnum, TypeDesc type)
{
llvm::Value* result = groupdata_field_ref(fieldnum);
std::string llname = llnamefmt("{}_ptr", m_groupdata_field_names[fieldnum]);
llvm::Value* result = ll.void_ptr(groupdata_field_ref(fieldnum));
if (type != TypeDesc::UNKNOWN)
result = ll.ptr_to_cast(result, llvm_type(type), llname);
else
result = ll.void_ptr(result, llname);
result = ll.ptr_to_cast(result, llvm_type(type));
return result;
}
@@ -805,6 +969,8 @@ BackendLLVM::llvm_call_function(const char* name, cspan<const Symbol*> args,
const Symbol& s = *(args[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, /*follow*/ true);
else if (s.typespec().simpletype().aggregate > 1
|| (deriv_ptrs && s.has_derivs()))
valargs[i] = llvm_void_ptr(s);
@@ -814,8 +980,6 @@ BackendLLVM::llvm_call_function(const char* name, cspan<const Symbol*> args,
return ll.call_function(name, cspan<llvm::Value*>(valargs, args.size()));
}
llvm::Value*
BackendLLVM::llvm_test_nonzero(Symbol& val, bool test_derivs)
{
@@ -889,8 +1053,8 @@ BackendLLVM::llvm_assign_impl(Symbol& Result, Symbol& Src, int arrayindex,
// the size difference is intended (by the optimizer).
if (result_t.is_array() && src_t.is_array() && arrayindex == -1) {
OSL_DASSERT(assignable(result_t.elementtype(), src_t.elementtype()));
llvm::Value* resultptr = llvm_get_pointer(Result);
llvm::Value* srcptr = llvm_get_pointer(Src);
llvm::Value* resultptr = llvm_void_ptr(Result);
llvm::Value* srcptr = llvm_void_ptr(Src);
int len = std::min(Result.size(), Src.size());
int align = result_t.is_closure_based()
? (int)sizeof(void*)
@@ -911,7 +1075,10 @@ BackendLLVM::llvm_assign_impl(Symbol& Result, Symbol& Src, int arrayindex,
TypeDesc basetype = TypeDesc::BASETYPE(rt.basetype);
const int num_components = rt.aggregate;
const bool singlechan = (srccomp != -1) || (dstcomp != -1);
if (!singlechan) {
if (use_optix() && Src.typespec().is_string()) {
llvm::Value* src = llvm_load_device_string(Src, /*follow*/ true);
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()
+36 -57
View File
@@ -122,23 +122,22 @@ public:
int component = 0,
TypeDesc cast = TypeDesc::UNKNOWN)
{
return llvm_load_value(sym, deriv, NULL, component, cast);
return (use_optix() && !sym.typespec().is_closure()
&& sym.typespec().is_string())
? llvm_load_device_string(sym, /*follow*/ true)
: llvm_load_value(sym, deriv, NULL, component, cast);
}
/// Load the address of a global device-side string pointer, which may
/// reside in a global variable, the groupdata struct, or a local value.
llvm::Value* llvm_load_device_string(const Symbol& sym, bool follow);
/// Convenience function to load a string for CPU or GPU device
llvm::Value* llvm_load_string(const Symbol& sym)
{
OSL_DASSERT(sym.typespec().is_string());
return llvm_load_value(sym);
}
/// Convenience function to load a constant string for CPU or GPU device.
/// On the GPU, we use the ustring hash, not the character pointer.
llvm::Value* llvm_load_string(ustring str) { return ll.constant(str); }
llvm::Value* llvm_load_string(string_view str)
{
return llvm_load_string(ustring(str));
return use_optix() ? llvm_load_device_string(sym, /*follow*/ true)
: llvm_load_value(sym);
}
/// Legacy version
@@ -149,12 +148,10 @@ public:
return llvm_load_value(sym, deriv, NULL, component, cast);
}
/// Return an llvm::Value* in the form that we will pass a float-based
/// symbol as a function argument to any "built-in" OSL function -- as a
/// simple value if the symbol is a scalar and no derivs are needed, or as
/// a pointer to the data in all other cases (aggregates, arrays, or
/// derivs needed). If deriv == true and sym doesn't have derivs, coerce
/// it into a variable having derivatives set to 0.0.
/// Return an llvm::Value* that is either a scalar and derivs is
/// false, or a pointer to sym's values (if sym is an aggregate or
/// derivs == true). Furthermore, if deriv == true and sym doesn't
/// have derivs, coerce it into a variable with zero derivs.
llvm::Value* llvm_load_arg(const Symbol& sym, bool derivs);
/// Just like llvm_load_arg(sym,deriv), except use use sym's derivs
@@ -219,16 +216,16 @@ public:
/// 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);
llvm::Value* getOrAllocateCUDAVariable(const Symbol& sym,
bool addMetadata = false);
/// Create a named CUDA global variable with the given type, size, and
/// alignment, and add it to the current Module. It will be initialized
/// with data pointed to by init_data. A record will be also added to
/// m_const_map, and will be retrieved by subsequent calls to
/// getOrAllocateCUDAVariable().
llvm::Value* addCUDAGlobalVariable(const std::string& name, int size,
int alignment, const void* init_data,
TypeDesc type = TypeDesc::UNKNOWN);
/// Create a CUDA global variable and add it to the current Module
llvm::Value* addCUDAVariable(const std::string& name, int size,
int alignment, const void* data,
TypeDesc type = TypeDesc::UNKNOWN);
/// Create the extra semantic information needed for OptiX variables
void createOptixMetadata(const std::string& name, const Symbol& sym);
/// Retrieve an llvm::Value that is a pointer holding the start address
/// of the specified symbol. This always works for globals and params;
@@ -275,18 +272,14 @@ public:
///
llvm::Value* sg_void_ptr() { return ll.void_ptr(m_llvm_shaderglobals_ptr); }
/// Cast the pointer variable specified by val to a pointer to the
/// basic type comprising `type`.
llvm::Value* llvm_ptr_cast(llvm::Value* val, const TypeSpec& type,
const std::string& llname = {})
llvm::Value* llvm_ptr_cast(llvm::Value* val, const TypeSpec& type)
{
return ll.ptr_cast(val, type.simpletype(), llname);
return ll.ptr_cast(val, type.simpletype());
}
llvm::Value* llvm_void_ptr(const Symbol& sym, int deriv = 0)
{
return ll.void_ptr(llvm_get_pointer(sym, deriv),
llnamefmt("{}_voidptr", sym.mangled()));
return ll.void_ptr(llvm_get_pointer(sym, deriv));
}
/// Return the LLVM type handle for a structure of the common group
@@ -412,13 +405,9 @@ public:
TypeDesc llvm_typedesc(const TypeSpec& typespec)
{
if (typespec.is_closure_based())
return TypeDesc(TypeDesc::PTR, typespec.arraylength());
else if (use_optix() && typespec.is_string_based()) {
// On the OptiX side, we use the uint64 hash to represent a string
return TypeDesc(TypeDesc::UINT64, typespec.arraylength());
} else
return typespec.simpletype();
return typespec.is_closure_based()
? TypeDesc(TypeDesc::PTR, typespec.arraylength())
: typespec.simpletype();
}
/// Generate the appropriate llvm type definition for a TypeSpec
@@ -451,7 +440,7 @@ public:
llvm::BasicBlock* llvm_exit_instance_block()
{
if (!m_exit_instance_block) {
std::string name = llnamefmt("{}_{}_exit_", inst()->layername(),
std::string name = fmtformat("{}_{}_exit_", inst()->layername(),
inst()->id());
m_exit_instance_block = ll.new_basic_block(name);
}
@@ -494,18 +483,6 @@ public:
LLVM_Util ll;
// Utility for constructing names for llvm symbols. It creates a formatted
// string if the shading system's "llvm_output_bitcode" option is set,
// otherwise it takes a shortcut and returns an empty string (since nobody
// is going to see the pretty bitcode anyway).
template<typename Str, typename... Args>
OSL_NODISCARD inline std::string llnamefmt(const Str& fmt,
Args&&... args) const
{
return m_name_llvm_syms ? fmtformat(fmt, std::forward<Args>(args)...)
: std::string();
}
private:
std::vector<int> m_layer_remap; ///< Remapping of layer ordering
std::set<int> m_layers_already_run; ///< List of layers run
@@ -531,16 +508,18 @@ private:
llvm::Type* m_llvm_type_closure_component; // LLVM type for ClosureComponent
llvm::PointerType* m_llvm_type_prepare_closure_func;
llvm::PointerType* m_llvm_type_setup_closure_func;
int m_llvm_local_mem; // Amount of memory we use for locals
bool m_name_llvm_syms; // Whether to name LLVM symbols
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;
// Name of each indexed field in the groupdata, mostly for debugging.
std::vector<std::string> m_groupdata_field_names;
// 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?
bool m_use_rs_bitcode; /// To use free function versions of Renderer Service functions.
friend class ShadingSystemImpl;
+13 -1
View File
@@ -240,7 +240,7 @@ private:
static constexpr OpcodeTest no_test = nullptr;
// Map opcode names to a Dependency info
std::unordered_map<ustring, Dependency> m_lookup;
std::unordered_map<ustring, Dependency, ustringHash> m_lookup;
/// Return the ptr to the symbol that is the argnum-th argument to the
/// given op in the instance.
@@ -2303,6 +2303,17 @@ struct Analyzer {
}
}
void make_closures_varying()
{
// We assume that closures are always stored as varying pointers
FOREACH_PARAM(Symbol & s, inst())
{
if (s.typespec().is_closure()) {
recursively_mark_varying(&s);
}
}
}
void push_varying_of_upstream_connections()
{
OSL_DEV_ONLY(std::cout << "connections to layer begin" << std::endl);
@@ -2395,6 +2406,7 @@ BatchedAnalysis::analyze_layer(ShaderInstance* inst)
analyzer.push_varying_of_shader_globals();
analyzer.make_interpolated_parameters_varying();
analyzer.make_renderer_outputs_varying();
analyzer.make_closures_varying();
analyzer.push_varying_of_upstream_connections();
analyzer.push_varying_of_implicitly_varying_ops();
+6 -8
View File
@@ -188,7 +188,7 @@ BatchedBackendLLVM::llvm_pass_type(const TypeSpec& typespec)
else if (t == TypeDesc::INT)
lt = ll.type_int();
else if (t == TypeDesc::STRING)
lt = (llvm::Type*)ll.type_ustring();
lt = (llvm::Type*)ll.type_string();
else if (t.aggregate == TypeDesc::VEC3)
lt = (llvm::Type*)ll.type_void_ptr(); //llvm_type_triple_ptr();
else if (t.aggregate == TypeDesc::MATRIX44)
@@ -867,7 +867,7 @@ BatchedBackendLLVM::llvm_load_value(llvm::Value* ptr, const TypeSpec& type,
|| (ll.llvm_typeof(result) == ll.type_float())
|| (ll.llvm_typeof(result) == ll.type_triple())
|| (ll.llvm_typeof(result) == ll.type_int())
|| (ll.llvm_typeof(result) == ll.type_ustring())
|| (ll.llvm_typeof(result) == (llvm::Type*)ll.type_string())
|| (ll.llvm_typeof(result) == ll.type_matrix())
|| (ll.llvm_typeof(result) == ll.type_longlong())) {
result = ll.widen_value(result);
@@ -888,7 +888,7 @@ BatchedBackendLLVM::llvm_load_value(llvm::Value* ptr, const TypeSpec& type,
(ll.llvm_typeof(result) == ll.type_wide_float())
|| (ll.llvm_typeof(result) == ll.type_wide_int())
|| (ll.llvm_typeof(result) == ll.type_wide_triple())
|| (ll.llvm_typeof(result) == ll.type_wide_ustring())
|| (ll.llvm_typeof(result) == ll.type_wide_string())
|| (ll.llvm_typeof(result) == ll.type_wide_bool())
|| (ll.llvm_typeof(result) == ll.type_wide_matrix())
|| (ll.llvm_typeof(result) == ll.type_wide_longlong()));
@@ -1218,8 +1218,7 @@ BatchedBackendLLVM::llvm_store_value(llvm::Value* new_val, llvm::Value* dst_ptr,
if (!type.is_closure_based() && t.aggregate > 1)
dst_ptr = ll.GEP(dst_ptr, 0, component);
if ((const llvm::Type*)ll.type_ptr(ll.llvm_typeof(new_val))
!= ll.llvm_typeof(dst_ptr)) {
if (ll.type_ptr(ll.llvm_typeof(new_val)) != ll.llvm_typeof(dst_ptr)) {
std::cerr << " new_val type=";
{
llvm::raw_os_ostream os_cerr(std::cerr);
@@ -1232,7 +1231,7 @@ BatchedBackendLLVM::llvm_store_value(llvm::Value* new_val, llvm::Value* dst_ptr,
}
std::cerr << std::endl;
}
OSL_ASSERT((const llvm::Type*)ll.type_ptr(ll.llvm_typeof(new_val))
OSL_ASSERT(ll.type_ptr(ll.llvm_typeof(new_val))
== ll.llvm_typeof(dst_ptr));
// Finally, store the value.
@@ -1767,8 +1766,7 @@ BatchedBackendLLVM::llvm_test_nonzero(const Symbol& val, bool test_derivs)
llvm::Value* llvmValue = llvm_get_pointer(val);
//OSL_DEV_ONLY(std::cout << "llvmValue type=" << ll.llvm_typenameof(llvmValue) << std::endl);
if (ll.llvm_typeof(llvmValue)
== (const llvm::Type*)ll.type_ptr(ll.type_bool())) {
if (ll.llvm_typeof(llvmValue) == ll.type_ptr(ll.type_bool())) {
return ll.op_ne(llvm_load_value(val), ll.constant_bool(0));
} else {
return ll.op_ne(llvm_load_value(val), ll.constant(0));
+84 -16
View File
@@ -1263,6 +1263,7 @@ LLVMGEN(llvm_gen_add)
OSL_ASSERT(!A.typespec().is_array() && !B.typespec().is_array());
if (Result.typespec().is_closure()) {
OSL_ASSERT(A.typespec().is_closure() && B.typespec().is_closure());
OSL_ASSERT(!A.is_uniform() && !B.is_uniform() && !result_is_uniform);
llvm::Value* valargs[] = { rop.sg_void_ptr(), rop.llvm_void_ptr(Result),
rop.llvm_void_ptr(A), rop.llvm_void_ptr(B),
rop.ll.mask_as_int(rop.ll.current_mask()) };
@@ -1676,6 +1677,7 @@ LLVMGEN(llvm_gen_modulus)
int num_components = type.aggregate;
#if 0
if (is_float && !op_is_uniform) {
// llvm 5.0.1 did not do a good job with op_mod when its
// parameters were <16xf32>. So we will go ahead
@@ -1702,7 +1704,9 @@ LLVMGEN(llvm_gen_modulus)
}
rop.ll.call_function(rop.build_name(func_spec), call_args);
} else {
} else
#endif
{
for (int i = 0; i < num_components; i++) {
llvm::Value* a = rop.loadLLVMValue(A, i, 0, type, op_is_uniform);
llvm::Value* b = rop.loadLLVMValue(B, i, 0, type, op_is_uniform);
@@ -7064,7 +7068,8 @@ LLVMGEN(llvm_gen_spline)
static void
llvm_gen_keyword_fill(BatchedBackendLLVM& rop, Opcode& op,
const ClosureRegistry::ClosureEntry* clentry,
ustring clname, llvm::Value* mem_void_ptr, int argsoffset)
ustring clname, llvm::Value* mem_void_ptr, int argsoffset,
int lane_index)
{
OSL_DASSERT(((op.nargs() - argsoffset) % 2) == 0);
@@ -7088,10 +7093,45 @@ llvm_gen_keyword_fill(BatchedBackendLLVM& rop, Opcode& op,
if (equivalent(p.type, ValueType) && !strcmp(key->c_str(), p.key)) {
// store data
OSL_DASSERT(p.offset + p.field_size <= clentry->struct_size);
llvm::Value* dst = rop.ll.offset_ptr(mem_void_ptr, p.offset);
llvm::Value* src = rop.llvm_void_ptr(Value);
rop.ll.op_memcpy(dst, src, (int)p.type.size(),
4 /* use 4 byte alignment for now */);
bool arg_is_uniform = Value.is_uniform();
TypeDesc simpletype(Value.typespec().simpletype());
// We don't currently offer a helper macro in genclosure.h for creating
// keyword array parameters, so perhaps we can assume we don't need to
// support them
OSL_DASSERT(simpletype.arraylen == 0);
int num_components = simpletype.aggregate;
llvm::Value* dest_base = rop.ll.offset_ptr(mem_void_ptr,
p.offset);
dest_base = rop.llvm_ptr_cast(dest_base, p.type);
for (int c = 0; c < num_components; c++) {
llvm::Value* dest_elem;
if (num_components > 1)
dest_elem = rop.ll.GEP(dest_base, 0, c);
else
dest_elem = dest_base;
// NOTE: We don't want any uniform arguments to be
// widened, so our typical op_is_uniform doesn't do what we
// want for this when loading. So just pass arg_is_uniform
// which will avoid widening any uniform arguments.
llvm::Value* loaded
= rop.llvm_load_value(Value, 0, NULL, c,
TypeDesc::UNKNOWN,
/*op_is_uniform*/ arg_is_uniform,
/*index_is_uniform*/ true);
if (!arg_is_uniform) {
loaded = rop.ll.op_extract(loaded, lane_index);
}
rop.ll.op_unmasked_store(loaded, dest_elem);
}
legal = true;
break;
}
@@ -7180,6 +7220,7 @@ LLVMGEN(llvm_gen_closure)
rop.ll.type_ptr(rop.llvm_type_closure_component_wide_ptr()));
llvm::Value* comp_wide_ptr = rop.ll.op_load(comp_wide_ptr_ptr);
llvm::Value* mask = rop.ll.current_mask();
// This is an unrolled vector-width loop. It was unrolled because it's
// was more expedient to write the for in C++ than IR, but if compilation
// of the extra ops becomes problematic, this choice can be revisited
@@ -7193,14 +7234,16 @@ LLVMGEN(llvm_gen_closure)
// For the weighted closures, we need a surrounding "if" so that it's safe
// for osl_allocate_weighted_closure_component to return NULL (unless we
// know for sure that it's constant weighted and that the weight is
// not zero).
// not zero). We also need the surrounding "if" to reject writing
// to closures that aren't masked.
llvm::BasicBlock* next_block = NULL;
llvm::BasicBlock* notnull_block = rop.ll.new_basic_block(
"non_null_closure");
next_block = rop.ll.new_basic_block("");
llvm::Value* cond
= rop.ll.op_ne(rop.ll.ptr_cast(comp_ptr, rop.ll.type_void_ptr()),
rop.ll.void_ptr_null());
"non_null_and_masked_closure");
next_block = rop.ll.new_basic_block("");
llvm::Value* cond = rop.ll.op_and(
rop.ll.op_ne(rop.ll.ptr_cast(comp_ptr, rop.ll.type_void_ptr()),
rop.ll.void_ptr_null()),
rop.ll.test_mask_lane(mask, lane_index));
rop.ll.op_branch(cond, notnull_block, next_block);
// If the closure has a "prepare" method, call
@@ -7233,7 +7276,30 @@ LLVMGEN(llvm_gen_closure)
int num_components = simpletype.aggregate;
llvm::Value* dest_base = rop.ll.offset_ptr(mem_void_ptr, p.offset);
dest_base = rop.llvm_ptr_cast(dest_base, p.type);
llvm::Type* dest_type = rop.ll.llvm_type(
static_cast<const TypeSpec&>(p.type).simpletype());
dest_base = rop.ll.ptr_to_cast(dest_base, dest_type);
if (num_elements > 1) {
OSL_DASSERT(rop.ll.is_type_array(dest_type));
// The type is an array type,
// which means our pointer is to an array type,
// not to &[0] (the address of the 1st element).
// IE: typedef int Int5Array[5];
// Int5Array *dest_base;
// in contrast to what most of use might consider an array pointer
// int *dest_base;
// So if we dereference Int5Array* to with [4], the 5th element,
// we would be really be pointing to ((int *)dest_base)[5*4] which is
// out of bounds of our 1 instance of Int5Array.
// Thus when dealing with arrays we will just dereference it and get the address to get
// the address of the 1st element.
dest_base = rop.ll.GEP(dest_type, dest_base, 0, 0);
llvm::Type* element_type = rop.ll.element_type_of(dest_type);
dest_type = element_type;
}
for (int a = 0; a < num_elements; ++a) {
llvm::Value* arrind = simpletype.arraylen ? rop.ll.constant(a)
@@ -7241,7 +7307,9 @@ LLVMGEN(llvm_gen_closure)
for (int c = 0; c < num_components; c++) {
llvm::Value* dest_elem;
if (num_components > 1)
dest_elem = rop.ll.GEP(dest_base, a, c);
dest_elem = rop.ll.GEP(dest_type, dest_base, a, c);
else if (num_elements > 1)
dest_elem = rop.ll.GEP(dest_type, dest_base, a);
else
dest_elem = dest_base;
@@ -7275,7 +7343,7 @@ LLVMGEN(llvm_gen_closure)
}
llvm_gen_keyword_fill(rop, op, clentry, closure_name, mem_void_ptr,
2 + weighted + clentry->nformal);
2 + weighted + clentry->nformal, lane_index);
if (next_block)
rop.ll.op_branch(next_block);
@@ -7706,7 +7774,7 @@ LLVMGEN(llvm_gen_pointcloud_write)
TypeDesc::NOSEMANTICS, nattrs } };
TypeSpec valuesArrayType { TypeDesc { TypeDesc::PTR, TypeDesc::SCALAR,
TypeDesc::NOSEMANTICS, nattrs } };
llvm::Value* names = rop.ll.op_alloca(rop.ll.type_ustring(), nattrs);
llvm::Value* names = rop.ll.op_alloca(rop.ll.type_string(), nattrs);
llvm::Value* types = rop.ll.op_alloca(rop.ll.type_typedesc(), nattrs);
llvm::Value* values = rop.ll.op_alloca(rop.ll.type_void_ptr(), nattrs);
+21 -5
View File
@@ -760,10 +760,11 @@ BatchedBackendLLVM::llvm_type_batched_trace_options()
std::vector<llvm::Type*> sg_types;
// Uniform values of the batch
sg_types.push_back(ll.type_float()); // mindist
sg_types.push_back(ll.type_float()); // maxdist
sg_types.push_back(ll.type_int()); // shade
sg_types.push_back(ll.type_ustring()); // traceset
sg_types.push_back(ll.type_float()); // mindist
sg_types.push_back(ll.type_float()); // maxdist
sg_types.push_back(ll.type_int()); // shade
sg_types.push_back(
reinterpret_cast<llvm::Type*>(ll.type_string())); // traceset
m_llvm_type_batched_trace_options = ll.type_struct(sg_types, "TraceOptions",
false /*is_packed*/);
@@ -1251,7 +1252,8 @@ BatchedBackendLLVM::llvm_assign_initial_value(
data_type = ll.type_float();
} else if (elemtype.is_string()) {
ptr_type = ll.type_ustring_ptr();
data_type = ll.type_ustring();
data_type = static_cast<llvm::Type*>(
ll.type_string());
} else if (elemtype.is_int()) {
ptr_type = ll.type_int_ptr();
data_type = ll.type_int();
@@ -1813,6 +1815,7 @@ BatchedBackendLLVM::build_llvm_init()
FOREACH_PARAM(Symbol & sym, gi)
{
if (sym.typespec().is_closure_based()) {
OSL_ASSERT(sym.is_varying());
int arraylen = std::max(1, sym.typespec().arraylength());
llvm::Value* val = ll.constant_ptr(NULL, ll.type_void_ptr());
if (!sym.is_uniform())
@@ -2691,9 +2694,21 @@ BatchedBackendLLVM::run()
// entry points, as well as for all the external functions that are
// just declarations (not definitions) in the module (which we have
// conveniently stashed in external_function_names).
#if 0
std::vector<std::string> entry_function_names;
entry_function_names.push_back (ll.func_name(init_func));
for (int layer = 0; layer < nlayers; ++layer) {
// set_inst (layer);
llvm::Function* f = funcs[layer];
if (f && group().is_entry_layer(layer))
entry_function_names.push_back (ll.func_name(f));
}
ll.internalize_module_functions ("osl_", external_function_names, entry_function_names);
#else
std::unordered_set<llvm::Function*> external_functions;
external_functions.insert(init_func);
for (int layer = 0; layer < nlayers; ++layer) {
// set_inst (layer);
llvm::Function* f = funcs[layer];
// If we plan to call bitcode_string of a layer's function after optimization
// it may not exist after optimization unless we treat it as external.
@@ -2702,6 +2717,7 @@ BatchedBackendLLVM::run()
}
}
ll.prune_and_internalize_module(external_functions);
#endif
// Debug code to dump the pre-optimized bitcode to a file
if (llvm_debug() >= 2 || shadingsys().llvm_output_bitcode()) {
+6 -4
View File
@@ -117,6 +117,7 @@ BatchedRendererServices<WidthT>::resolve_udim_uniform(
if (!texture_handle)
texture_handle = texturesys()->get_texture_handle(filename,
texture_thread_info);
#if OPENIMAGEIO_VERSION >= 20307
if (texturesys()->is_udim(texture_handle)) {
// Newer versions of the TextureSystem interface are able to determine the
// specific UDIM tile we're using.
@@ -130,9 +131,9 @@ BatchedRendererServices<WidthT>::resolve_udim_uniform(
udim_handle = texture_handle;
}
return udim_handle;
} else {
} else
#endif
return texture_handle;
}
}
@@ -150,6 +151,7 @@ BatchedRendererServices<WidthT>::resolve_udim(
if (!texture_handle)
texture_handle = texturesys()->get_texture_handle(filename,
texture_thread_info);
#if OPENIMAGEIO_VERSION >= 20307
if (texturesys()->is_udim(texture_handle)) {
// Newer versions of the TextureSystem interface are able to determine the
// specific UDIM tile we're using.
@@ -165,9 +167,9 @@ BatchedRendererServices<WidthT>::resolve_udim(
}
wresult[l] = udim_handle;
});
} else {
} else
#endif
assign_all(wresult, texture_handle);
}
}
+6 -1
View File
@@ -248,10 +248,10 @@ UNARY_OP_IMPL(log10)
UNARY_OP_IMPL(exp)
UNARY_OP_IMPL(exp2)
UNARY_OP_IMPL(expm1)
BINARY_OP_IMPL(pow)
UNARY_OP_IMPL(erf)
UNARY_OP_IMPL(erfc)
BINARY_OP_IMPL(pow)
DECL(osl_pow_vvf, "xXXf")
DECL(osl_pow_dvdvdf, "xXXX")
DECL(osl_pow_dvvdf, "xXXX")
@@ -285,7 +285,12 @@ DECL(osl_fabs_ii, "ii")
UNARY_OP_IMPL(abs)
UNARY_OP_IMPL(fabs)
BINARY_OP_IMPL(fmod)
DECL(osl_fmod_vvf, "xXXf")
DECL(osl_fmod_dvdvdf, "xXXX")
DECL(osl_fmod_dvvdf, "xXXX")
DECL(osl_fmod_dvdvf, "xXXf")
DECL(osl_smoothstep_ffff, "ffff")
DECL(osl_smoothstep_dfffdf, "xXffX")
+3 -4
View File
@@ -128,10 +128,9 @@ ShadingContext::execute_init(ShaderGroup& sgroup, int shadeindex,
RunLLVMGroupFunc run_func = sgroup.llvm_compiled_init();
if (!run_func)
return false;
ssg.context = this;
ssg.shadingStateUniform = &(shadingsys().m_shading_state_uniform);
ssg.renderer = renderer();
ssg.Ci = NULL;
ssg.context = this;
ssg.renderer = renderer();
ssg.Ci = NULL;
run_func(&ssg, m_heap.get(), userdata_base_ptr, output_base_ptr,
shadeindex);
}
+1 -1
View File
@@ -115,7 +115,7 @@ private:
};
typedef std::unordered_map<Query, QueryResult, QueryHash> QueryMap;
typedef std::unordered_map<ustring, int> DocMap;
typedef std::unordered_map<ustring, int, ustringHash> DocMap;
ShadingContext* m_context; // back-pointer to shading context
+1 -16
View File
@@ -244,22 +244,7 @@ ShaderInstance::parameters(const ParamValueList& params)
valuetype = TypeDesc::FLOAT;
}
// Relaxed rules just look to see that the types are isomorphic to each other (ie: same number of base values)
// Note that:
// * basetypes must match exactly (int vs float vs string)
// * valuetype cannot be unsized (we must know the concrete number of values)
// * if paramtype is sized (or not an array) just check for the total number of entries
// * if paramtype is unsized (shader writer is flexible about how many values come in) -- make sure we are a multiple of the target type
// * allow a single float setting a vec3 (or equivalent)
if (!(valuetype.basetype == paramtype.basetype
&& !valuetype.is_unsized_array()
&& ((!paramtype.is_unsized_array()
&& valuetype.basevalues() == paramtype.basevalues())
|| (paramtype.is_unsized_array()
&& valuetype.basevalues() % paramtype.aggregate
== 0)
|| (paramtype.is_vec3()
&& valuetype == TypeDesc::FLOAT)))) {
if (!relaxed_equivalent(sm_typespec, valuetype)) {
// We are being very relaxed in this mode, so if the user _still_ got it wrong
// something more serious is at play and we should treat it as an error.
shadingsys().errorfmt(
+137 -40
View File
@@ -6,11 +6,6 @@
#include <OpenImageIO/fmath.h>
#ifdef OSL_USE_OPTIX
# include <optix.h>
#endif
#include "oslexec_pvt.h"
#include <OSL/genclosure.h>
#include "backendllvm.h"
@@ -284,7 +279,7 @@ LLVMGEN(llvm_gen_printf)
const char* format = format_ustring.c_str();
std::string s;
int arg = format_arg + 1;
size_t optix_size = 0; // how much buffer size does optix need?
size_t optix_size = 0;
while (*format != '\0') {
if (*format == '%') {
if (format[1] == '%') {
@@ -350,19 +345,42 @@ LLVMGEN(llvm_gen_printf)
s += " ";
s += ourformat;
llvm::Value* 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);
// Ensure that 64-bit values are aligned to 8-byte boundaries
optix_size = (optix_size + sizeof(double) - 1)
& ~(sizeof(double) - 1);
optix_size += sizeof(double);
} else if (simpletype.basetype == TypeDesc::INT)
optix_size += sizeof(int);
else if (simpletype.basetype == TypeDesc::STRING)
llvm::Value* loaded = nullptr;
if (rop.use_optix()
&& simpletype.basetype == TypeDesc::STRING) {
// In the OptiX case, we register each string separately.
if (simpletype.arraylen >= 1) {
// Mangle the element's name in case llvm_load_device_string calls getOrAllocateLLVMSymbol
ustring name
= ustring::fmtformat("__symname__{}[{}]",
sym.mangled(), a);
Symbol lsym(name, TypeDesc::TypeString,
sym.symtype());
lsym.set_dataptr(SymArena::Absolute,
&((ustring*)sym.dataptr())[a]);
loaded
= rop.llvm_load_device_string(lsym,
/*follow*/ true);
} else {
loaded
= rop.llvm_load_device_string(sym,
/*follow*/ true);
}
optix_size += sizeof(uint64_t);
} 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);
// Ensure that 64-bit values are aligned to 8-byte boundaries
optix_size = (optix_size + sizeof(double) - 1)
& ~(sizeof(double) - 1);
optix_size += sizeof(double);
} else if (simpletype.basetype == TypeDesc::INT)
optix_size += sizeof(int);
}
call_args.push_back(loaded);
}
}
@@ -379,8 +397,10 @@ LLVMGEN(llvm_gen_printf)
// is no argument.
if (rop.use_optix() && arg == format_arg + 1) {
call_args.push_back(rop.ll.void_ptr_null());
#if OPTIX_VERSION >= 70000
// we push the size of the arguments on the stack
optix_size += sizeof(uint64_t);
#endif
}
// Some ops prepend things
@@ -391,33 +411,58 @@ LLVMGEN(llvm_gen_printf)
// Now go back and put the new format string in its place
if (!rop.use_optix()) {
call_args[new_format_slot] = rop.llvm_load_string(s);
call_args[new_format_slot] = rop.ll.constant(s.c_str());
} else {
// In OptiX7+ case, we do this:
// In OptiX 6 we do this:
// void* args = { arg0, arg1, arg2 };
// osl_printf(sg, fmt, args);
// vprintf(fmt, args);
// However, in the OptiX7+ case, we do this:
// void* args = { args_size, arg0, arg1, arg2 };
// (where args_size is the size of arg0 + arg1 + arg2...)
//
// Make sure host has the format string so it can print it
call_args[new_format_slot] = rop.llvm_load_string(s);
size_t nargs = call_args.size() - (new_format_slot + 1);
// Allocate space to store the arguments to osl_printf().
// Don't forget to pad a little extra to hold the size of the arguments itself.
llvm::Value* voids = rop.ll.op_alloca(
rop.ll.type_char(), optix_size + sizeof(uint64_t),
fmtformat("printf_argbuf_L{}sz{}_", op.sourceline(), optix_size),
8);
#if !defined(OSL_USE_OPTIX) || OPTIX_VERSION < 70000
Symbol sym(format_sym.name(), format_sym.typespec(),
format_sym.symtype());
format_ustring = s;
sym.set_dataptr(SymArena::Absolute, &format_ustring);
call_args[new_format_slot] = rop.ll.int_to_ptr_cast(
rop.llvm_load_device_string(sym, /*follow*/ true));
#else
// Make sure host has the format string so it can print it
format_ustring = s;
rop.shadingsys().renderer()->register_string(format_ustring.string(),
"");
call_args[new_format_slot] = rop.ll.int_to_ptr_cast(
rop.ll.constant64(format_ustring.hash()));
#endif
size_t nargs = call_args.size() - (new_format_slot + 1);
// Allocate space to store the arguments to osl_printf().
#if !defined(OSL_USE_OPTIX) || OPTIX_VERSION < 70000
llvm::Value* voids = rop.ll.op_alloca(rop.ll.type_char(), optix_size,
std::string(), 8);
#else
// Don't forget to pad a little extra to hold the size of the arguments itself.
llvm::Value* voids = rop.ll.op_alloca(rop.ll.type_char(),
optix_size + sizeof(uint64_t),
std::string(), 8);
#endif
#if defined(OSL_USE_OPTIX) && OPTIX_VERSION >= 70000
// Size of the collection of arguments comes before all the arguments
{
llvm::Value* args_size = rop.ll.constant64(optix_size);
llvm::Value* memptr = rop.ll.offset_ptr(voids, 0);
llvm::Value* iptr = rop.ll.ptr_cast(memptr,
rop.ll.type_longlong_ptr(),
"printf_argbuf_as_llptr");
rop.ll.type_longlong_ptr());
rop.ll.op_store(args_size, iptr);
}
optix_size = sizeof(
uint64_t); // first 'args' element is the size of the argument list
#else
optix_size = 0;
#endif
for (size_t i = 0; i < nargs; ++i) {
llvm::Value* arg = call_args[new_format_slot + 1 + i];
if (arg->getType()->isFloatingPointTy()
@@ -959,7 +1004,6 @@ LLVMGEN(llvm_gen_select)
&& Result.typespec().is_float_based());
int num_components = type.aggregate;
int x_components = X.typespec().aggregate();
OSL_DASSERT(x_components <= 3);
bool derivs = (Result.has_derivs() && (A.has_derivs() || B.has_derivs()));
llvm::Value* zero = X.typespec().is_int() ? rop.ll.constant(0)
@@ -1556,8 +1600,23 @@ LLVMGEN(llvm_gen_construct_triple)
else if (op.opname() == "normal")
vectype = TypeDesc::NORMAL;
llvm::Value* from_arg = rop.llvm_load_value(Space);
llvm::Value* to_arg = rop.llvm_load_string(Strings::common);
llvm::Value* from_arg = nullptr;
llvm::Value* to_arg = nullptr;
if (!rop.use_optix()) {
from_arg = rop.llvm_load_value(Space);
to_arg = rop.ll.constant(Strings::common);
} else {
// Create a Symbol for Strings::common. The symbol name isn't important,
// since a new name will be created based on the string hash.
//
// TODO: This pattern is used elsewhere (e.g., in llvm_assign_initial_value),
// so it might make sense to refactor it.
Symbol to_sym(ustring("Strings__common"), TypeDesc::TypeString,
SymTypeConst);
to_sym.set_dataptr(SymArena::Absolute, (void*)&Strings::common);
from_arg = rop.llvm_load_device_string(Space, /*follow*/ true);
to_arg = rop.llvm_load_device_string(to_sym, /*follow*/ true);
}
llvm::Value* args[] = { rop.sg_void_ptr(),
rop.llvm_void_ptr(Result),
@@ -1864,6 +1923,28 @@ LLVMGEN(llvm_gen_compare_op)
llvm::Value* final_result = 0;
ustring opname = op.opname();
if (rop.use_optix() && A.typespec().is_string()) {
OSL_DASSERT(B.typespec().is_string()
&& "Only string-to-string comparison is supported");
llvm::Value* a = rop.llvm_load_device_string(A, /*follow*/ true);
llvm::Value* b = rop.llvm_load_device_string(B, /*follow*/ true);
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.
OSL_ASSERT(0 && "OptiX only supports equality testing for strings");
}
OSL_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.
@@ -2994,9 +3075,20 @@ LLVMGEN(llvm_gen_getattribute)
// necessary conversions from its internal format to OSL's.
TypeDesc dest_type = Destination.typespec().simpletype();
llvm::Value* obj_name_arg = object_lookup ? rop.llvm_load_value(ObjectName)
: rop.llvm_load_string(ustring());
llvm::Value* attr_name_arg = rop.llvm_load_value(Attribute);
llvm::Value* obj_name_arg = NULL;
llvm::Value* attr_name_arg = NULL;
if (rop.use_optix()) {
// We need to make a DeviceString for the parameter names
if (object_lookup)
obj_name_arg = rop.llvm_load_device_string(ObjectName, true);
else
obj_name_arg = rop.ll.constant(ustring());
attr_name_arg = rop.llvm_load_device_string(Attribute, true);
} else {
obj_name_arg = object_lookup ? rop.llvm_load_value(ObjectName)
: rop.ll.constant(ustring());
attr_name_arg = rop.llvm_load_value(Attribute);
}
llvm::Value* args[] = {
rop.sg_void_ptr(),
@@ -3423,8 +3515,13 @@ LLVMGEN(llvm_gen_closure)
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,
/*follow*/ false);
rop.ll.op_memcpy(dst, src, 8, 8);
} 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(),
@@ -3636,7 +3733,7 @@ LLVMGEN(llvm_gen_pointcloud_write)
int nattrs = (op.nargs() - 3) / 2;
// Generate local space for the names/types/values arrays
llvm::Value* names = rop.ll.op_alloca(rop.ll.type_ustring(), nattrs);
llvm::Value* names = rop.ll.op_alloca(rop.ll.type_string(), nattrs);
llvm::Value* types = rop.ll.op_alloca(rop.ll.type_typedesc(), nattrs);
llvm::Value* values = rop.ll.op_alloca(rop.ll.type_void_ptr(), nattrs);
+94 -37
View File
@@ -18,15 +18,11 @@
#include <OpenImageIO/sysutil.h>
#include <OpenImageIO/timer.h>
#ifdef OSL_USE_OPTIX
# include <optix.h>
#endif
#include "../liboslcomp/oslcomp_pvt.h"
#include "oslexec_pvt.h"
#include "backendllvm.h"
// Create external declarations for all built-in funcs we may call from LLVM
// Create extrenal declarations for all built-in funcs we may call from LLVM
#define DECL(name, signature) extern "C" void name();
#include "builtindecl.h"
#undef DECL
@@ -216,7 +212,6 @@ BackendLLVM::llvm_type_sg()
sg_types.push_back(vp); // opaque tracedata*
sg_types.push_back(vp); // opaque objdata*
sg_types.push_back(vp); // ShadingContext*
sg_types.push_back(vp); // OpaqueShadingStateUniformPtr
sg_types.push_back(vp); // RendererServices*
sg_types.push_back(vp); // object2common
sg_types.push_back(vp); // shader2common
@@ -250,7 +245,6 @@ BackendLLVM::llvm_type_groupdata()
std::vector<llvm::Type*> fields;
int offset = 0;
int order = 0;
m_groupdata_field_names.clear();
if (llvm_debug() >= 2)
std::cout << "Group param struct:\n";
@@ -262,7 +256,6 @@ BackendLLVM::llvm_type_groupdata()
<< " at offset " << offset << "\n";
int sz = (m_num_used_layers + 3) & (~3); // Round up to 32 bit boundary
fields.push_back(ll.type_array(ll.type_bool(), sz));
m_groupdata_field_names.emplace_back("layer_runflags");
offset += sz * sizeof(bool);
++order;
@@ -278,7 +271,6 @@ BackendLLVM::llvm_type_groupdata()
int* offsets = &group().m_userdata_offsets[0];
int sz = (nuserdata + 3) & (~3);
fields.push_back(ll.type_array(ll.type_bool(), sz));
m_groupdata_field_names.emplace_back("userdata_init_flags");
offset += nuserdata * sizeof(bool);
++order;
for (int i = 0; i < nuserdata; ++i) {
@@ -292,8 +284,6 @@ BackendLLVM::llvm_type_groupdata()
: type.numelements();
type.arraylen = n;
fields.push_back(llvm_type(type));
m_groupdata_field_names.emplace_back(
fmtformat("userdata{}_{}_", i, names[i]));
// Alignment
int align = type.basesize();
offset = OIIO::round_to_multiple_of_pow2(offset, align);
@@ -324,8 +314,6 @@ BackendLLVM::llvm_type_groupdata()
const int derivSize = (sym.has_derivs() ? 3 : 1);
ts.make_array(arraylen * derivSize);
fields.push_back(llvm_type(ts));
m_groupdata_field_names.emplace_back(
fmtformat("lay{}param_{}_", layer, sym.name()));
// FIXME(arena) -- temporary debugging
if (debug() && sym.symtype() == SymTypeOutputParam
@@ -359,8 +347,9 @@ BackendLLVM::llvm_type_groupdata()
if (llvm_debug() >= 2)
print(" Group struct had {} fields, total size {}\n\n", order, offset);
m_llvm_type_groupdata = ll.type_struct(fields, "Groupdata");
OSL_ASSERT(fields.size() == m_groupdata_field_names.size());
std::string groupdataname = fmtformat("Groupdata_{}",
group().name().hash());
m_llvm_type_groupdata = ll.type_struct(fields, groupdataname);
return m_llvm_type_groupdata;
}
@@ -409,10 +398,11 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force)
if (!force && sym.valuesource() == Symbol::ConnectedVal
&& !sym.typespec().is_closure_based())
return;
// For "globals" that are closures, there is nothing to initialize.
if (sym.typespec().is_closure_based() && sym.symtype() == SymTypeGlobal)
return;
int arraylen = std::max(1, sym.typespec().arraylength());
// Closures need to get their storage before anything can be
// assigned to them. Unless they are params, in which case we took
// care of it in the group entry point.
@@ -422,11 +412,9 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force)
return;
}
// For local variables (including temps), when "debug_uninit" is enabled,
// we store special values in the variable to make it easier to detect
// uninitialized use.
if ((sym.symtype() == SymTypeLocal || sym.symtype() == SymTypeTemp)
&& shadingsys().debug_uninit()) {
// Handle the "debug uninitialized values" case
bool isarray = sym.typespec().is_array();
int alen = isarray ? sym.typespec().arraylength() : 1;
llvm::Value* u = NULL;
@@ -437,7 +425,7 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force)
else if (sym.typespec().is_int_based())
u = ll.constant(std::numeric_limits<int>::min());
else if (sym.typespec().is_string_based())
u = llvm_load_string(Strings::uninitialized_string);
u = ll.constant(Strings::uninitialized_string);
if (u) {
for (int a = 0; a < alen; ++a) {
llvm::Value* aval = isarray ? ll.constant(a) : NULL;
@@ -448,7 +436,6 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force)
return;
}
// Local/temp strings are always initialized to the empty string.
if ((sym.symtype() == SymTypeLocal || sym.symtype() == SymTypeTemp)
&& sym.typespec().is_string_based()) {
// Strings are pointers. Can't take any chance on leaving
@@ -457,10 +444,6 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force)
return; // we're done, the parts below are just for params
}
// FIXME: Future work -- how expensive would it be to initialize all
// locals to 0? We should test this for performance hit, and if
// reasonable, it may be a good idea to do it by default.
// From here on, everything we are dealing with is a shader parameter
// (either ordinary or output).
OSL_ASSERT_MSG(sym.symtype() == SymTypeParam
@@ -470,7 +453,7 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force)
// Handle interpolated params by calling osl_bind_interpolated_param,
// which will check if userdata is already retrieved, if not it will
// call RendererServices::get_userdata to retrieve it. In either case,
// call RendererServices::get_userdata to retrived it. In either case,
// it will return 1 if it put the userdata in the right spot (either
// retrieved de novo or copied from a previous retrieval), or 0 if no
// such userdata was available.
@@ -510,9 +493,23 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force)
ll.op_memset(ll.offset_ptr(dstptr, size), 0, 2 * size);
} else {
// No pre-placement: fall back to call to the renderer callback.
llvm::Value* name_arg = NULL;
if (use_optix()) {
// We need to make a DeviceString for the parameter name
ustring arg_name = ustring::fmtformat("osl_paramname_{}_{}",
symname, sym.layer());
Symbol symname_const(arg_name, TypeDesc::TypeString,
SymTypeConst);
symname_const.set_dataptr(SymArena::Absolute, &symname);
name_arg = llvm_load_device_string(symname_const,
/*follow*/ true);
} else {
name_arg = ll.constant(symname);
}
llvm::Value* args[] = {
sg_void_ptr(),
llvm_load_string(symname),
name_arg,
ll.constant(type),
ll.constant((int)group().m_userdata_derivs[userdata_index]),
groupdata_field_ptr(2 + userdata_index), // userdata data ptr
@@ -532,12 +529,12 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force)
llvm_void_ptr(sym),
ll.constant((int)sym.has_derivs()),
sg_void_ptr(),
llvm_load_string(inst()->shadername()),
ll.constant(ustring(inst()->shadername())),
ll.constant(0),
llvm_load_string(sym.unmangled()),
ll.constant(sym.unmangled()),
ll.constant(0),
ll.constant(ncomps),
llvm_load_string("<get_userdata>") };
ll.constant("<get_userdata>") };
ll.call_function("osl_naninf_check", args);
}
// userdata pre-placement always succeeds, we don't need to bother
@@ -560,16 +557,32 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force)
if (sym.has_init_ops() && sym.valuesource() == Symbol::DefaultVal) {
// Handle init ops.
build_llvm_code(sym.initbegin(), sym.initend());
} else if (use_optix() && !sym.typespec().is_closure()) {
} else if (use_optix() && !sym.typespec().is_closure()
&& !sym.typespec().is_string()) {
// If the call to osl_bind_interpolated_param returns 0, the default
// value needs to be loaded from a CUDA variable.
llvm::Value* cuda_var = getOrAllocateCUDAVariable(sym);
ustring var_name = ustring::fmtformat("{}_{}_{}_{}", sym.name(),
inst()->layername(),
group().name(), group().id());
// The "true" argument triggers the creation of the metadata needed to
// make the variable visible to OptiX.
llvm::Value* cuda_var = getOrAllocateCUDAVariable(sym, true);
// memcpy the initial value from the CUDA variable
llvm::Value* src = ll.ptr_cast(ll.GEP(cuda_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_closure()) {
// For convenience, we always pack string addresses into the groupdata
// struct.
int userdata_index = find_userdata_index(sym);
llvm::Value* init_val = getOrAllocateCUDAVariable(sym);
init_val = ll.ptr_cast(init_val, ll.type_void_ptr());
ll.op_memcpy(groupdata_field_ptr(2 + userdata_index), init_val, 8,
4);
} else if (!sym.lockgeom() && !sym.typespec().is_closure()) {
// geometrically-varying param; memcpy its default value
TypeDesc t = sym.typespec().simpletype();
@@ -581,7 +594,6 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force)
// Use default value
int num_components = sym.typespec().simpletype().aggregate;
TypeSpec elemtype = sym.typespec().elementtype();
int arraylen = std::max(1, sym.typespec().arraylength());
for (int a = 0, c = 0; a < arraylen; ++a) {
llvm::Value* arrind = sym.typespec().is_array() ? ll.constant(a)
: NULL;
@@ -593,7 +605,7 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force)
if (elemtype.is_float_based())
init_val = ll.constant(sym.get_float(c));
else if (elemtype.is_string())
init_val = llvm_load_string(sym.get_string(c));
init_val = ll.constant(sym.get_string(c));
else if (elemtype.is_int())
init_val = ll.constant(sym.get_int(c));
OSL_DASSERT(init_val);
@@ -859,8 +871,8 @@ BackendLLVM::build_llvm_init()
{
// Make a group init function: void group_init(ShaderGlobals*, GroupData*)
// Note that the GroupData* is passed as a void*.
std::string unique_name = fmtformat("__direct_callable__group_{}_init",
group().name());
std::string unique_name = fmtformat("__direct_callable__group_{}_{}_init",
group().name(), group().id());
ll.current_function(
ll.make_function(unique_name, false,
ll.type_void(), // return type
@@ -1364,6 +1376,19 @@ BackendLLVM::run()
#ifdef OSL_LLVM_NO_BITCODE
OSL_ASSERT(!use_rs_bitcode());
ll.module(ll.new_module("llvm_ops"));
# ifdef OSL_USE_OPTIX
if (use_optix()) {
// If the module is created from LLVM bitcode, the target and
// data layout is inherited from that, but if creating an empty
// module like here, have to manually set those, otherwise
// compiling will later fail because the NVPTX target is not found.
// The target triple and data layout used here are those specified
// for NVPTX (https://www.llvm.org/docs/NVPTXUsage.html#triples).
ll.module()->setDataLayout(
"e-i64:64-i128:128-v16:16-v32:32-n16:32:64");
ll.module()->setTargetTriple("nvptx64-nvidia-cuda");
}
# endif
#else
if (!use_optix()) {
if (use_rs_bitcode()) {
@@ -1502,6 +1527,21 @@ BackendLLVM::run()
if (shadingsys().llvm_prune_ir_strategy() == "none") {
// Do nothing! This is only useful for testing how much we reduce
// optimization and JIT time with the other strategies.
} else if (shadingsys().llvm_prune_ir_strategy() == "internalize") {
// Mark as 'internal' all functions that start with "osl_" but are
// but are not among the known entry points. LLVM can then quickly
// realize that any 'internal' functions not called can be
// discarded. This was our original stab at this strategy.
std::vector<std::string> entry_function_names;
entry_function_names.push_back(ll.func_name(init_func));
for (int layer = 0; layer < nlayers; ++layer) {
// set_inst (layer);
llvm::Function* f = funcs[layer];
if (f && group().is_entry_layer(layer))
entry_function_names.push_back(ll.func_name(f));
}
ll.internalize_module_functions("osl_", external_function_names,
entry_function_names);
} else /* if (shadingsys().llvm_prune_ir_strategy() == "prune") */ {
// New (2020) and default behavior, from Alex Wells:
// Full prune of uncalled functions, and marking as 'internal' to
@@ -1606,8 +1646,25 @@ BackendLLVM::run()
}
if (use_optix()) {
ll.ptx_compile_group(nullptr, group().name().string(),
std::string name = fmtformat("{}_{}", group().name(), group().id());
#if (OPTIX_VERSION < 70000)
// Create an llvm::Module from the renderer-supplied library bitcode
std::vector<char>& bitcode = shadingsys().m_lib_bitcode;
OSL_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");
ll.ptx_compile_group(lib_module, name,
group().m_llvm_ptx_compiled_version);
#else
ll.ptx_compile_group(nullptr, name,
group().m_llvm_ptx_compiled_version);
#endif
if (group().m_llvm_ptx_compiled_version.empty()) {
OSL_ASSERT(0 && "Unable to generate PTX");
}
+148 -82
View File
@@ -92,10 +92,6 @@
#include <llvm/Transforms/Utils/Cloning.h>
#include <llvm/Transforms/Utils/SymbolRewriter.h>
#ifdef OSL_USE_OPTIX
# include <optix.h>
#endif
OSL_NAMESPACE_ENTER
@@ -446,6 +442,8 @@ LLVM_Util::LLVM_Util(const PerThreadInfo& per_thread_info, int debuglevel,
*m_llvm_context);
m_llvm_type_float_ptr = (llvm::PointerType*)llvm::Type::getFloatPtrTy(
*m_llvm_context);
m_llvm_type_ustring_ptr
= (llvm::PointerType*)llvm::PointerType::get(m_llvm_type_char_ptr, 0);
m_llvm_type_longlong_ptr = (llvm::PointerType*)llvm::Type::getInt64PtrTy(
*m_llvm_context);
m_llvm_type_void_ptr = m_llvm_type_char_ptr;
@@ -476,10 +474,12 @@ LLVM_Util::LLVM_Util(const PerThreadInfo& per_thread_info, int debuglevel,
m_llvm_type_wide_longlong = llvm_vector_type(m_llvm_type_longlong,
m_vector_width);
m_llvm_type_wide_char_ptr = llvm::PointerType::get(m_llvm_type_wide_char,
0);
m_llvm_type_wide_void_ptr = llvm_vector_type(m_llvm_type_void_ptr,
m_vector_width);
m_llvm_type_wide_char_ptr = llvm::PointerType::get(m_llvm_type_wide_char,
0);
m_llvm_type_wide_ustring_ptr = llvm_vector_type(m_llvm_type_char_ptr,
m_vector_width);
m_llvm_type_wide_void_ptr = llvm_vector_type(m_llvm_type_void_ptr,
m_vector_width);
m_llvm_type_wide_int_ptr = llvm::PointerType::get(m_llvm_type_wide_int, 0);
m_llvm_type_wide_bool_ptr = llvm::PointerType::get(m_llvm_type_wide_bool,
0);
@@ -493,28 +493,6 @@ LLVM_Util::LLVM_Util(const PerThreadInfo& per_thread_info, int debuglevel,
// A matrix is a struct composed 16 floats
std::vector<llvm::Type*> matrix_wide_fields(16, m_llvm_type_wide_float);
m_llvm_type_wide_matrix = type_struct(matrix_wide_fields, "WideMatrix4");
ustring_rep(m_ustring_rep); // setup ustring-related types
}
void
LLVM_Util::ustring_rep(UstringRep rep)
{
m_ustring_rep = rep;
m_llvm_type_ustring = llvm::Type::getInt8PtrTy(*m_llvm_context);
// ^^ When m_ustring_rep != UstringRep::charptr, we'd ideally want to make
// it a uint directly, but that is wreaking havoc with function
// signatures, so continue to disguise it as a pointer.
// m_llvm_type_ustring = (sizeof(size_t) == sizeof(uint64_t))
// ? llvm::Type::getInt64Ty(*m_llvm_context)
// : llvm::Type::getInt32Ty(*m_llvm_context);
m_llvm_type_ustring_ptr = llvm::PointerType::get(m_llvm_type_ustring, 0);
m_llvm_type_wide_ustring = llvm_vector_type(m_llvm_type_ustring,
m_vector_width);
m_llvm_type_wide_ustring_ptr
= llvm::PointerType::get(m_llvm_type_wide_ustring, 0);
}
@@ -2437,12 +2415,89 @@ LLVM_Util::validate_global_mappings(
// DEPRECATED(1.13)
// Soon to be deprecated
void
LLVM_Util::internalize_module_functions(
const std::string& prefix, const std::vector<std::string>& exceptions,
const std::vector<std::string>& moreexceptions)
{
for (llvm::Function& func : module()->getFunctionList()) {
llvm::Function* sym = &func;
std::string symname = sym->getName().str();
if (prefix.size() && !OIIO::Strutil::starts_with(symname, prefix))
continue;
bool needed = false;
for (size_t i = 0, e = exceptions.size(); i < e; ++i)
if (sym->getName() == exceptions[i]) {
needed = true;
// std::cout << " necessary LLVM module function "
// << sym->getName().str() << "\n";
break;
}
for (size_t i = 0, e = moreexceptions.size(); i < e; ++i)
if (sym->getName() == moreexceptions[i]) {
needed = true;
// std::cout << " necessary LLVM module function "
// << sym->getName().str() << "\n";
break;
}
if (!needed) {
llvm::GlobalValue::LinkageTypes linkage = sym->getLinkage();
// std::cout << " unnecessary LLVM module function "
// << sym->getName().str() << " linkage " << int(linkage) << "\n";
if (linkage == llvm::GlobalValue::ExternalLinkage)
sym->setLinkage(llvm::GlobalValue::LinkOnceODRLinkage);
// ExternalLinkage means it's potentially externally callable,
// and so will definitely have code generated.
// LinkOnceODRLinkage keeps one copy so it can be inlined or
// called internally to the module, but allows it to be
// discarded otherwise.
}
}
#if 0
// I don't think we need to worry about linkage of global symbols, but
// here is an example of how to iterate over the globals anyway.
for (llvm::Module::global_iterator iter = module()->global_begin(); iter != module()->global_end(); iter++) {
llvm::GlobalValue *sym = llvm::dyn_cast<llvm::GlobalValue>(iter);
if (!sym)
continue;
std::string symname = sym->getName();
if (prefix.size() && ! OIIO::Strutil::starts_with(symname, prefix))
continue;
bool needed = false;
for (size_t i = 0, e = exceptions.size(); i < e; ++i)
if (sym->getName() == exceptions[i]) {
needed = true;
break;
}
if (! needed) {
llvm::GlobalValue::LinkageTypes linkage = sym->getLinkage();
// std::cout << " unnecessary LLVM global " << sym->getName().str()
// << " linkage " << int(linkage) << "\n";
if (linkage == llvm::GlobalValue::ExternalLinkage)
f->setLinkage (llvm::GlobalValue::LinkOnceODRLinkage);
}
}
#endif
}
llvm::Function*
LLVM_Util::make_function(const std::string& name, bool fastcall,
llvm::Type* rettype, llvm::Type* arg1,
llvm::Type* arg2, llvm::Type* arg3, llvm::Type* arg4)
{
std::vector<llvm::Type*> argtypes;
if (arg1)
argtypes.emplace_back(arg1);
if (arg2)
argtypes.emplace_back(arg2);
if (arg3)
argtypes.emplace_back(arg3);
if (arg4)
argtypes.emplace_back(arg4);
return make_function(name, fastcall, rettype, argtypes, false);
}
@@ -2495,9 +2550,9 @@ LLVM_Util::current_function_arg(int a)
llvm::BasicBlock*
LLVM_Util::new_basic_block(const std::string& name)
{
std::string n = fmtformat("bb_{}{}{}", name, name.size() ? "_" : "",
m_next_serial_bb++);
return llvm::BasicBlock::Create(context(), n, current_function());
return llvm::BasicBlock::Create(context(),
debug() ? name : llvm::Twine::createNull(),
current_function());
}
@@ -2654,7 +2709,7 @@ LLVM_Util::type_struct(cspan<llvm::Type*> types, const std::string& name,
llvm::PointerType*
llvm::Type*
LLVM_Util::type_ptr(llvm::Type* type)
{
return llvm::PointerType::get(type, 0);
@@ -2673,7 +2728,18 @@ LLVM_Util::type_array(llvm::Type* type, int n)
return llvm::ArrayType::get(type, n);
}
bool
LLVM_Util::is_type_array(llvm::Type* type)
{
return type->isArrayTy();
}
llvm::Type*
LLVM_Util::element_type_of(llvm::Type* array_type)
{
OSL_DASSERT(is_type_array(array_type));
return array_type->getArrayElementType();
}
llvm::FunctionType*
LLVM_Util::type_function(llvm::Type* rettype, cspan<llvm::Type*> params,
@@ -2847,28 +2913,30 @@ LLVM_Util::constant_ptr(void* p, llvm::PointerType* type)
llvm::Value*
LLVM_Util::constant(ustring s)
{
const size_t size_t_bits = sizeof(size_t) * 8;
// Create a const size_t with the ustring character address, or hash,
// depending on the representation we're using.
size_t p = (ustring_rep() == UstringRep::charptr) ? size_t(s.c_str())
: s.hash();
auto str = (size_t_bits == 64) ? constant64(p) : constant(int(p));
// Then cast the int to a char*. Ideally, we would only do that if the rep
// were a charptr, but we disguise the hashes as char*'s also to avoid
// ugliness with function signatures differing between CPU and GPU.
// Maybe some day we'll use the hash representation on both sides?
return builder().CreateIntToPtr(str, m_llvm_type_ustring,
"ustring constant");
// Create a const size_t with the ustring contents
size_t bits = sizeof(size_t) * 8;
llvm::Value* str
= llvm::ConstantInt::get(context(),
llvm::APInt(bits, size_t(s.c_str()), true));
// Then cast the int to a char*.
return builder().CreateIntToPtr(str, type_string(), "ustring constant");
}
llvm::Value*
LLVM_Util::wide_constant(ustring s)
{
return builder().CreateVectorSplat(m_vector_width, constant(s));
}
// Create a const size_t with the ustring contents
size_t bits = sizeof(size_t) * 8;
llvm::Value* str
= llvm::ConstantInt::get(context(),
llvm::APInt(bits, size_t(s.c_str()), true));
// Then cast the int to a char*.
llvm::Value* constant_value = builder().CreateIntToPtr(str, type_string(),
"ustring constant");
return builder().CreateVectorSplat(m_vector_width, constant_value);
}
llvm::Value*
@@ -3424,7 +3492,7 @@ LLVM_Util::llvm_type(const TypeDesc& typedesc)
else if (t == TypeDesc::INT)
lt = type_int();
else if (t == TypeDesc::STRING)
lt = type_ustring();
lt = type_string();
else if (t.aggregate == TypeDesc::VEC3)
lt = type_triple();
else if (t.aggregate == TypeDesc::MATRIX44)
@@ -3433,8 +3501,6 @@ LLVM_Util::llvm_type(const TypeDesc& typedesc)
lt = type_void();
else if (t == TypeDesc::UINT8)
lt = type_char();
else if (t == TypeDesc::UINT64)
lt = type_longlong();
else if (t == TypeDesc::PTR)
lt = type_void_ptr();
else {
@@ -3470,7 +3536,7 @@ LLVM_Util::llvm_vector_type(const TypeDesc& typedesc)
else if (t == TypeDesc::INT)
lt = type_wide_int();
else if (t == TypeDesc::STRING)
lt = type_wide_ustring();
lt = type_wide_string();
else if (t.aggregate == TypeDesc::VEC3)
lt = type_wide_triple();
else if (t.aggregate == TypeDesc::MATRIX44)
@@ -3504,7 +3570,7 @@ LLVM_Util::offset_ptr(llvm::Value* ptr, llvm::Value* offset,
if (offset)
i = op_add(i, offset);
ptr = int_to_ptr_cast(i);
if (ptrtype && ptrtype != type_void_ptr())
if (ptrtype)
ptr = ptr_cast(ptr, ptrtype);
return ptr;
}
@@ -3514,8 +3580,6 @@ LLVM_Util::offset_ptr(llvm::Value* ptr, llvm::Value* offset,
llvm::Value*
LLVM_Util::offset_ptr(llvm::Value* ptr, int offset, llvm::Type* ptrtype)
{
if (offset == 0)
return ptr; // shortcut for 0 offset
return offset_ptr(ptr, constant(size_t(offset)), ptrtype);
}
@@ -3545,9 +3609,10 @@ LLVM_Util::op_alloca(llvm::Type* llvmtype, int n, const std::string& name,
llvm::BasicBlock* entry_block = &current_function()->getEntryBlock();
m_builder->SetInsertPoint(entry_block, entry_block->begin());
llvm::ConstantInt* numalloc = (llvm::ConstantInt*)constant(n);
llvm::AllocaInst* allocainst = builder().CreateAlloca(llvmtype, numalloc,
name);
llvm::ConstantInt* numalloc = (llvm::ConstantInt*)constant(n);
llvm::AllocaInst* allocainst
= builder().CreateAlloca(llvmtype, numalloc,
debug() ? name : llvm::Twine::createNull());
if (align > 0) {
#if OSL_LLVM_VERSION >= 110
using AlignmentType = llvm::Align;
@@ -4095,7 +4160,7 @@ LLVM_Util::op_gather(llvm::Value* ptr, llvm::Value* wide_index)
return builder().CreateIntToPtr(op_combine_8x_vectors(gather1,
gather2),
type_wide_ustring());
type_wide_string());
}
case 8: {
// Gather 64bit integer, as that is binary compatible with 64bit pointers of ustring
@@ -4124,12 +4189,12 @@ LLVM_Util::op_gather(llvm::Value* ptr, llvm::Value* wide_index)
return builder().CreateIntToPtr(op_combine_4x_vectors(gather1,
gather2),
type_wide_ustring());
type_wide_string());
}
default: OSL_ASSERT(0 && "unsupported native bit mask width");
}
} else {
return clamped_gather_from_uniform(type_wide_ustring());
return clamped_gather_from_uniform(type_wide_string());
}
} else if (ptr->getType() == type_wide_float_ptr()) {
if (m_supports_avx512f) {
@@ -4302,7 +4367,8 @@ LLVM_Util::op_gather(llvm::Value* ptr, llvm::Value* wide_index)
} else {
return clamped_gather_from_varying(type_wide_int());
}
} else if (ptr->getType() == type_wide_ustring_ptr()) {
} else if (ptr->getType()
== llvm::PointerType::get(type_wide_string(), 0)) {
if (m_supports_avx512f) {
// TODO: Are we guaranteed a 64bit pointer?
switch (m_vector_width) {
@@ -4336,7 +4402,7 @@ LLVM_Util::op_gather(llvm::Value* ptr, llvm::Value* wide_index)
return builder().CreateIntToPtr(op_combine_8x_vectors(gather1,
gather2),
type_wide_ustring());
type_wide_string());
}
case 8: {
// Gather 64bit integer, as that is binary compatible with 64bit pointers of ustring
@@ -4376,7 +4442,7 @@ LLVM_Util::op_gather(llvm::Value* ptr, llvm::Value* wide_index)
return builder().CreateIntToPtr(op_combine_4x_vectors(gather1,
gather2),
type_wide_ustring());
type_wide_string());
}
default: OSL_ASSERT(0 && "unsupported native bit mask width");
}
@@ -4384,7 +4450,7 @@ LLVM_Util::op_gather(llvm::Value* ptr, llvm::Value* wide_index)
} else {
// AVX2 case falls through to here, choose not to specialize and use
// generic code gen as 4 AVX2 gathers would be required
return clamped_gather_from_varying(type_wide_ustring());
return clamped_gather_from_varying(type_wide_string());
}
} else {
@@ -4422,7 +4488,7 @@ LLVM_Util::op_scatter(llvm::Value* wide_val, llvm::Value* ptr,
llvm::BasicBlock* test_scatter_per_lane[MaxSupportedSimdLaneCount + 1];
for (int l = 0; l < m_vector_width; ++l) {
test_scatter_per_lane[l] = new_basic_block(
fmtformat("test scatter lane={}", l));
std::string("test scatter lane=").append(std::to_string(l)));
}
test_scatter_per_lane[m_vector_width] = new_basic_block(
"after scatter");
@@ -4446,7 +4512,7 @@ LLVM_Util::op_scatter(llvm::Value* wide_val, llvm::Value* ptr,
op_branch(test_scatter_per_lane[0]);
for (int l = 0; l < m_vector_width; ++l) {
llvm::BasicBlock* scatter_block = new_basic_block(
fmtformat("scatter lane={}", l));
std::string("scatter lane=").append(std::to_string(l)));
op_branch(mask_per_lane[l], scatter_block,
test_scatter_per_lane[l + 1]);
@@ -4521,7 +4587,7 @@ LLVM_Util::op_scatter(llvm::Value* wide_val, llvm::Value* ptr,
return;
}
} else if (ptr->getType() == type_ustring_ptr()) {
OSL_ASSERT(wide_val->getType() == type_wide_ustring());
OSL_ASSERT(wide_val->getType() == type_wide_string());
if (m_supports_avx512f) {
switch (m_vector_width) {
case 16: {
@@ -4676,8 +4742,9 @@ LLVM_Util::op_scatter(llvm::Value* wide_val, llvm::Value* ptr,
/*is_dest_wide*/ true);
return;
}
} else if (ptr->getType() == type_wide_ustring_ptr()) {
OSL_ASSERT(wide_val->getType() == type_wide_ustring());
} else if (ptr->getType()
== llvm::PointerType::get(type_wide_string(), 0)) {
OSL_ASSERT(wide_val->getType() == type_wide_string());
if (m_supports_avx512f) {
switch (m_vector_width) {
case 16: {
@@ -5834,6 +5901,13 @@ LLVM_Util::ptx_compile_group(llvm::Module* lib_module, const std::string& name,
failed = llvm::Linker::linkModules(*linked_module, std::move(lib_ptr));
}
# if (OPTIX_VERSION < 70000)
// Internalize the Globals to match code generated by NVCC
for (auto& g_var : linked_module->globals()) {
g_var.setLinkage(llvm::GlobalValue::InternalLinkage);
}
# endif
// Verify that the NVPTX target has been initialized
std::string error;
const llvm::Target* llvm_target
@@ -5908,16 +5982,8 @@ LLVM_Util::ptx_compile_group(llvm::Module* lib_module, const std::string& name,
// Run the optimization passes on the module to generate the PTX
mod_pm.run(*linked_module);
// In a multithreaded environment, llvm will return "callseq <ID>" comments
// with a non-deterministic ID, leading to OptiX JIT cache misses.
// Filter them out. TODO: Address upstream in llvm
std::istringstream raw_ptx(assembly_stream.str().str());
std::stringstream ptx_stream;
std::string line;
while (std::getline(raw_ptx, line)) {
ptx_stream << line.substr(0, line.find("// callseq")) << std::endl;
}
out = ptx_stream.str();
// TODO: Minimize string copying
out = assembly_stream.str().str();
delete linked_module;
+1 -1
View File
@@ -72,7 +72,7 @@ private:
int m_oso_major, m_oso_minor; ///< oso file format version
int m_sym_default_index; ///< Next sym default value to fill in
bool m_errors; ///< Did we hit any errors?
typedef std::unordered_map<ustring, int> UstringIntMap;
typedef std::unordered_map<ustring, int, ustringHash> UstringIntMap;
UstringIntMap m_symmap; ///< map sym name to index
};
+8 -9
View File
@@ -18,10 +18,6 @@
#include <OpenImageIO/fmath.h>
#ifdef __CUDACC__
# include <optix.h>
#endif
#include "opcolor.h"
#include "opcolor_impl.h"
@@ -233,12 +229,17 @@ rend_get_userdata(StringParam name, void* data, int data_size,
OSL_HOSTDEVICE void
ColorSystem::error(StringParam src, StringParam dst, Context sg) const
{
# ifndef __CUDA_ARCH__
# if !defined(__CUDA_ARCH__) || OPTIX_VERSION < 70000
const char* args[2] = { src.c_str(), dst.c_str() };
osl_printf(sg,
(char*) // FIXME!
"ERROR: Unknown color space transformation \"%s\" -> \"%s\"\n",
args);
# else
uint64_t fmt_hash = UStringHash::Hash(
"ERROR: Unknown color space transformation \"%s\" -> \"%s\"\n");
uint64_t args[3] = { 2 * sizeof(uint64_t), dst, src };
osl_printf(sg, (char*)fmt_hash, args);
# endif
}
@@ -265,11 +266,9 @@ ColorSystem::error(StringParam src, StringParam dst, Context context) const
}
static inline const ColorSystem&
op_color_colorsystem(void* sg_)
op_color_colorsystem(void* sg)
{
ShaderGlobals* sg = (ShaderGlobals*)sg_;
ShadingStateUniform* ssu = (ShadingStateUniform*)sg->shadingStateUniform;
return ssu->m_colorsystem;
return ((ShaderGlobals*)sg)->context->shadingsys().colorsystem();
}
static inline OSL::ShadingContext*
+8 -3
View File
@@ -50,8 +50,13 @@ clamp_zero(Color3& c)
//OSL_CONSTANT_DATA const float cie_colour_match[81][3] =
// Choose to access 1d array vs 2d to allow better code generation of gathers
namespace { // anon namespace to avoid duplicate OptiX symbols
static OSL_CONSTANT_DATA const float cie_colour_match[81 * 3] OSL_ALIGNAS(64) = {
// clang-format off
// clang-format off
#ifdef __CUDACC__
OSL_CONSTANT_DATA const float cie_colour_match[81*3] =
#else
OSL_CONSTANT_DATA const float cie_colour_match[81 * 3] OSL_ALIGNAS(64) =
#endif
{
0.0014,0.0000,0.0065, 0.0022,0.0001,0.0105, 0.0042,0.0001,0.0201,
0.0076,0.0002,0.0362, 0.0143,0.0004,0.0679, 0.0232,0.0006,0.1102,
0.0435,0.0012,0.2074, 0.0776,0.0022,0.3713, 0.1344,0.0040,0.6456,
@@ -79,8 +84,8 @@ static OSL_CONSTANT_DATA const float cie_colour_match[81 * 3] OSL_ALIGNAS(64) =
0.0007,0.0002,0.0000, 0.0005,0.0002,0.0000, 0.0003,0.0001,0.0000,
0.0002,0.0001,0.0000, 0.0002,0.0001,0.0000, 0.0001,0.0000,0.0000,
0.0001,0.0000,0.0000, 0.0001,0.0000,0.0000, 0.0000,0.0000,0.0000
// clang-format on
};
// clang-format on
} // namespace
+12 -15
View File
@@ -138,10 +138,10 @@ osl_transformn_dvmdv(void* result, void* M_, void* v_)
OSL_SHADEOP int
osl_get_matrix(void* sg_, void* r, const char* from)
{
ShaderGlobals* sg = (ShaderGlobals*)sg_;
ShadingStateUniform* ssu = (ShadingStateUniform*)sg->shadingStateUniform;
ShaderGlobals* sg = (ShaderGlobals*)sg_;
ShadingContext* ctx = (ShadingContext*)sg->context;
if (HDSTR(from) == STRING_PARAMS(common)
|| HDSTR(from) == ssu->m_commonspace_synonym) {
|| HDSTR(from) == ctx->shadingsys().commonspace_synonym()) {
MAT(r).makeIdentity();
return true;
}
@@ -157,7 +157,7 @@ osl_get_matrix(void* sg_, void* r, const char* from)
if (!ok) {
MAT(r).makeIdentity();
ShadingContext* ctx = (ShadingContext*)((ShaderGlobals*)sg)->context;
if (ssu->m_unknown_coordsys_error)
if (ctx->shadingsys().unknown_coordsys_error())
ctx->errorfmt("Unknown transformation \"{}\"", from);
}
return ok;
@@ -168,10 +168,10 @@ osl_get_matrix(void* sg_, void* r, const char* from)
OSL_SHADEOP int
osl_get_inverse_matrix(void* sg_, void* r, const char* to)
{
ShaderGlobals* sg = (ShaderGlobals*)sg_;
ShadingStateUniform* ssu = (ShadingStateUniform*)sg->shadingStateUniform;
ShaderGlobals* sg = (ShaderGlobals*)sg_;
ShadingContext* ctx = (ShadingContext*)sg->context;
if (HDSTR(to) == STRING_PARAMS(common)
|| HDSTR(to) == ssu->m_commonspace_synonym) {
|| HDSTR(to) == ctx->shadingsys().commonspace_synonym()) {
MAT(r).makeIdentity();
return true;
}
@@ -189,7 +189,7 @@ osl_get_inverse_matrix(void* sg_, void* r, const char* to)
if (!ok) {
MAT(r).makeIdentity();
ShadingContext* ctx = (ShadingContext*)((ShaderGlobals*)sg)->context;
if (ssu->m_unknown_coordsys_error)
if (ctx->shadingsys().unknown_coordsys_error())
ctx->errorfmt("Unknown transformation \"{}\"", to);
}
return ok;
@@ -207,21 +207,18 @@ osl_get_inverse_matrix(void* sg_, void* r, const char* to);
OSL_SHADEOP OSL_HOSTDEVICE int
osl_prepend_matrix_from(void* sg_, void* r, const char* from)
osl_prepend_matrix_from(void* sg, void* r, const char* from)
{
ShaderGlobals* sg = (ShaderGlobals*)sg_;
Matrix44 m;
bool ok = osl_get_matrix(sg, &m, from);
bool ok = osl_get_matrix((ShaderGlobals*)sg, &m, from);
if (ok)
MAT(r) = m * MAT(r);
#ifndef __CUDACC__
// TODO: How do we manage this in OptiX?
else {
ShadingStateUniform* ssu = (ShadingStateUniform*)sg->shadingStateUniform;
if (ssu->m_unknown_coordsys_error) {
ShadingContext* ctx = (ShadingContext*)(sg)->context;
ShadingContext* ctx = (ShadingContext*)((ShaderGlobals*)sg)->context;
if (ctx->shadingsys().unknown_coordsys_error())
ctx->errorfmt("Unknown transformation \"{}\"", from);
}
}
#endif
return ok;
+13 -13
View File
@@ -224,7 +224,7 @@ osl_texture(void* sg_, const char* name, void* handle, void* opt_, float s,
bool derivs = (dresultdx || dalphadx);
// It's actually faster to ask for 4 channels (even if we need fewer)
// and ensure that they're being put in aligned memory.
OIIO::simd::float4 result_simd, dresultds_simd, dresultdt_simd;
OIIO::simd::vfloat4 result_simd, dresultds_simd, dresultdt_simd;
bool ok = sg->renderer->texture(
USTR(name), (TextureSystem::TextureHandle*)handle,
sg->context->texture_thread_info(), *opt, sg, s, t, dsdx, dtdx, dsdy,
@@ -240,10 +240,10 @@ osl_texture(void* sg_, const char* name, void* handle, void* opt_, float s,
if (derivs) {
OSL_DASSERT((dresultdx == nullptr) == (dresultdy == nullptr));
OSL_DASSERT((dalphadx == nullptr) == (dalphady == nullptr));
OIIO::simd::float4 dresultdx_simd = dresultds_simd * dsdx
+ dresultdt_simd * dtdx;
OIIO::simd::float4 dresultdy_simd = dresultds_simd * dsdy
+ dresultdt_simd * dtdy;
OIIO::simd::vfloat4 dresultdx_simd = dresultds_simd * dsdx
+ dresultdt_simd * dtdx;
OIIO::simd::vfloat4 dresultdy_simd = dresultds_simd * dsdy
+ dresultdt_simd * dtdy;
if (dresultdx) {
for (int i = 0; i < chans; ++i)
((float*)dresultdx)[i] = dresultdx_simd[i];
@@ -281,7 +281,7 @@ osl_texture3d(void* sg_, const char* name, void* handle, void* opt_, void* P_,
bool derivs = (dresultdx != NULL || dalphadx != NULL);
// It's actually faster to ask for 4 channels (even if we need fewer)
// and ensure that they're being put in aligned memory.
OIIO::simd::float4 result_simd, dresultds_simd, dresultdt_simd,
OIIO::simd::vfloat4 result_simd, dresultds_simd, dresultdt_simd,
dresultdr_simd;
bool ok = sg->renderer->texture3d(
USTR(name), (TextureSystem::TextureHandle*)handle,
@@ -297,12 +297,12 @@ osl_texture3d(void* sg_, const char* name, void* handle, void* opt_, void* P_,
// Correct our str texture space gradients into xyz-space gradients
if (derivs) {
OIIO::simd::float4 dresultdx_simd = dresultds_simd * dPdx.x
+ dresultdt_simd * dPdx.y
+ dresultdr_simd * dPdx.z;
OIIO::simd::float4 dresultdy_simd = dresultds_simd * dPdy.x
+ dresultdt_simd * dPdy.y
+ dresultdr_simd * dPdy.z;
OIIO::simd::vfloat4 dresultdx_simd = dresultds_simd * dPdx.x
+ dresultdt_simd * dPdx.y
+ dresultdr_simd * dPdx.z;
OIIO::simd::vfloat4 dresultdy_simd = dresultds_simd * dPdy.x
+ dresultdt_simd * dPdy.y
+ dresultdr_simd * dPdy.z;
if (dresultdx) {
for (int i = 0; i < chans; ++i)
((float*)dresultdx)[i] = dresultdx_simd[i];
@@ -335,7 +335,7 @@ osl_environment(void* sg_, const char* name, void* handle, void* opt_, void* R_,
TextureOpt* opt = (TextureOpt*)opt_;
// It's actually faster to ask for 4 channels (even if we need fewer)
// and ensure that they're being put in aligned memory.
OIIO::simd::float4 local_result;
OIIO::simd::vfloat4 local_result;
bool ok = sg->renderer->environment(USTR(name),
(TextureSystem::TextureHandle*)handle,
sg->context->texture_thread_info(),
+41 -30
View File
@@ -19,11 +19,12 @@
// Pull in the modified Imath headers and the OSL_HOSTDEVICE macro
#ifdef __CUDACC__
# include <OSL/oslconfig.h>
# include <optix.h>
#endif
#ifdef __CUDACC__
# include "string_hash.h"
# if OPTIX_VERSION >= 70000
# include "string_hash.h"
# endif
#endif
#include <OpenImageIO/color.h>
@@ -33,7 +34,6 @@
#include <OpenImageIO/ustring.h>
#include "osl_pvt.h"
#include <OSL/dual.h>
#include <OSL/dual_vec.h>
#include <OSL/genclosure.h>
@@ -43,8 +43,6 @@
#include <OSL/oslexec.h>
#include <OSL/rendererservices.h>
#include <OSL/shaderglobals.h>
#include "shading_state_uniform.h"
#include "constantpool.h"
#include "opcolor.h"
@@ -60,6 +58,7 @@ using OIIO::ParamValueList;
using OIIO::RefCnt;
using OIIO::spin_lock;
using OIIO::spin_mutex;
using OIIO::ustringHash;
namespace Strutil = OIIO::Strutil;
@@ -192,8 +191,10 @@ struct UserDataNeeded {
{
if (a.name != b.name)
return a.name < b.name;
if (a.layer_num != b.layer_num)
return a.layer_num < b.layer_num;
// Checking for layer_num means that if derivs differ find_userdata_index
// may find the wrong layer symbol with the wrong derivs setting.
//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)
@@ -212,9 +213,11 @@ struct UserDataNeeded {
struct AttributeNeeded {
ustring name;
ustring scope;
TypeDesc type;
AttributeNeeded(ustring name, ustring scope = ustring())
: name(name), scope(scope)
AttributeNeeded(ustring name, ustring scope = ustring(),
TypeDesc type = TypeUnknown)
: name(name), scope(scope), type(type)
{
}
@@ -224,6 +227,15 @@ struct AttributeNeeded {
return a.name < b.name;
if (a.scope != b.scope)
return a.scope < b.scope;
if (a.type.basetype != b.type.basetype)
return a.type.basetype < b.type.basetype;
if (a.type.aggregate != b.type.aggregate)
return a.type.aggregate < b.type.aggregate;
if (a.type.arraylen != b.type.arraylen)
return a.type.arraylen < b.type.arraylen;
// Ignore vector semantics
// if (a.type.vecsemantics != b.type.vecsemantics)
// return a.type.vecsemantics < b.type.vecsemantics;
return false; // they are equal
}
};
@@ -617,10 +629,7 @@ public:
bool lockgeom_default() const { return m_lockgeom_default; }
bool strict_messages() const { return m_strict_messages; }
bool range_checking() const { return m_range_checking; }
bool unknown_coordsys_error() const
{
return m_shading_state_uniform.m_unknown_coordsys_error;
}
bool unknown_coordsys_error() const { return m_unknown_coordsys_error; }
bool connection_error() const { return m_connection_error; }
bool relaxed_param_typecheck() const { return m_relaxed_param_typecheck; }
int optimize() const { return m_optimize; }
@@ -645,10 +654,7 @@ public:
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_shading_state_uniform.m_commonspace_synonym;
}
ustring commonspace_synonym() const { return m_commonspace_synonym; }
bool llvm_jit_fma() const { return m_llvm_jit_fma; }
ustring llvm_jit_target() const { return m_llvm_jit_target; }
@@ -701,7 +707,8 @@ public:
void optimize_all_groups(int nthreads = 0, int mythread = 0,
int totalthreads = 1, bool do_jit = true);
typedef std::unordered_map<ustring, OpDescriptor> OpDescriptorMap;
typedef std::unordered_map<ustring, OpDescriptor, ustringHash>
OpDescriptorMap;
/// Look up OpDescriptor for the named op, return NULL for unknown op.
///
@@ -726,7 +733,7 @@ public:
void count_noise(int number = 1) { m_stat_noise_calls += number; }
ColorSystem& colorsystem() { return m_shading_state_uniform.m_colorsystem; }
ColorSystem& colorsystem() { return m_colorsystem; }
std::shared_ptr<OIIO::ColorConfig> colorconfig();
@@ -840,9 +847,10 @@ private:
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_connection_error; ///< Error for ConnectShaders to fail?
bool m_greedyjit; ///< JIT as much as we can?
bool m_countlayerexecs; ///< Count number of layer execs?
bool m_unknown_coordsys_error; ///< Error to use unknown xform name?
bool m_connection_error; ///< Error for ConnectShaders to fail?
bool m_greedyjit; ///< JIT as much as we can?
bool m_countlayerexecs; ///< Count number of layer execs?
bool m_relaxed_param_typecheck; ///< Allow parameters to be set from isomorphic types (same data layout)
int m_max_warnings_per_thread; ///< How many warnings to display per thread before giving up?
int m_profile; ///< Level of profiling of shader execution
@@ -891,6 +899,7 @@ private:
std::string m_library_searchpath; ///< Library search path
std::vector<std::string>
m_library_searchpath_dirs; ///< All library searchpath dirs
ustring m_commonspace_synonym; ///< Synonym for "common" space
std::vector<ustring> m_raytypes; ///< Names of ray types
std::vector<ustring> m_renderer_outputs; ///< Names of renderer outputs
std::vector<SymLocationDesc> m_symlocs;
@@ -906,10 +915,8 @@ private:
int m_gpu_opt_error; ///< Error on inability to optimize
///< away things that can't GPU.
ustring m_colorspace; ///< What RGB colors mean
ShadingStateUniform m_shading_state_uniform;
ustring m_colorspace; ///< What RGB colors mean
ColorSystem m_colorsystem; ///< Data for current colorspace
std::shared_ptr<OIIO::ColorConfig>
m_colorconfig; ///< OIIO/OCIO color configuration
@@ -1353,7 +1360,7 @@ public:
{
return (symbols().size() == 0
&& (ops().size() == 0 ||
#ifdef __CUDA_ARCH__
#if defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000
(ops().size() == 1
&& UStringHash::Hash(ops()[0].opname().c_str())
== STRING_PARAMS(end))
@@ -1925,13 +1932,16 @@ private:
std::vector<void*> m_userdata_init_vals;
std::vector<ustring> m_attributes_needed;
std::vector<ustring> m_attribute_scopes;
std::vector<TypeDesc> m_attribute_types;
std::vector<ustring> m_renderer_outputs; ///< Names of renderer outputs
std::vector<SymLocationDesc> m_symlocs; ///< SORTED!!
bool m_unknown_textures_needed;
bool m_unknown_closures_needed;
bool m_unknown_attributes_needed;
atomic_ll m_executions { 0 }; ///< Number of times the group executed
atomic_ll m_stat_total_shading_time_ticks { 0 }; // Shading time (ticks)
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;
@@ -2359,7 +2369,8 @@ private:
nullptr, &OIIO::aligned_free
};
size_t m_heapsize = 0;
using RegexMap = std::unordered_map<ustring, std::unique_ptr<std::regex>>;
using RegexMap
= std::unordered_map<ustring, std::unique_ptr<std::regex>, ustringHash>;
RegexMap m_regex_map; ///< Compiled regex's
MessageList m_messages; ///< Message blackboard
#if OSL_USE_BATCHED
@@ -2573,7 +2584,7 @@ public:
std::string layer_function_name(const ShaderGroup& group,
const ShaderInstance& inst)
{
return fmtformat("{}_{}", group.name(), inst.layername());
return fmtformat("{}_{}_{}", group.name(), inst.layername(), inst.id());
}
std::string layer_function_name()
{
+1 -1
View File
@@ -27,7 +27,7 @@
#pragma clang diagnostic ignored "-Wparentheses-equality"
#endif
#if OSL_CLANG_VERSION >= 150000
#if (OSL_CLANG_VERSION >= 150000) || (OSL_INTEL_CLANG_VERSION >= 140000)
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#endif
+2 -21
View File
@@ -288,7 +288,8 @@ public:
}
// TODO: This is really the only part of parsing that needs the lock still.
// But the calling code setting locale complicates this.
// The calling code no longer sets the global locale, so it would
// likely be simple to clean this up.
//
bool parse(OSOReader* reader, const char* what) {
yy_switch_to_buffer(m_buffer, m_scanner);
@@ -310,12 +311,6 @@ OSOReader::parse_file (const std::string &filename)
// can actually be reading a .oso file at a time.
std::lock_guard<std::mutex> guard (osoread_mutex);
// Force classic "C" locale for correct '.' decimal parsing.
// N.B. This is not safe in a multi-threaded program where another
// application thread is expecting the native locale to work properly.
std::locale oldlocale; // save the previous native locale
std::locale::global (std::locale::classic());
FILE* osoin = OIIO::Filesystem::fopen (filename, "r");
if (! osoin) {
m_err.errorfmt("File {} not found", filename);
@@ -326,7 +321,6 @@ OSOReader::parse_file (const std::string &filename)
bool ok = scope.parse(this, filename.c_str());
fclose (osoin);
std::locale::global (oldlocale); // Restore the original locale.
return ok;
}
@@ -339,22 +333,9 @@ OSOReader::parse_memory (const std::string &buffer)
// can actually be reading a .oso file at a time.
std::lock_guard<std::mutex> guard (osoread_mutex);
#ifndef OIIO_STRUTIL_HAS_STOF
// Force classic "C" locale for correct '.' decimal parsing.
// N.B. This is not safe in a multi-threaded program where another
// application thread is expecting the native locale to work properly.
// This is not necessary for versions of OIIO that have Strutil::stof,
// and we can remove it entirely when OIIO 1.9 is the minimum.
std::locale oldlocale = std::locale::global (std::locale::classic());
#endif
Scope scope(buffer);
bool ok = scope.parse(this, "preloaded OSO code");
#ifndef OIIO_STRUTIL_HAS_STOF
std::locale::global (oldlocale); // Restore the original locale.
#endif
return ok;
}
+2 -1
View File
@@ -12,7 +12,8 @@ OSL_NAMESPACE_ENTER
namespace pvt {
#ifdef USE_PARTIO
typedef std::unordered_map<ustring, std::unique_ptr<PointCloud>> PointCloudMap;
typedef std::unordered_map<ustring, std::unique_ptr<PointCloud>, ustringHash>
PointCloudMap;
static PointCloudMap pointclouds;
static OIIO::spin_mutex pointcloudmap_mutex;
+2 -2
View File
@@ -22,8 +22,8 @@ public:
~PointCloud();
static PointCloud* get(ustring filename, bool write = false);
typedef std::unordered_map<ustring,
std::unique_ptr<Partio::ParticleAttribute>>
typedef std::unordered_map<
ustring, std::unique_ptr<Partio::ParticleAttribute>, ustringHash>
AttributeMap;
const Partio::ParticlesData* read_access() const
+4 -1
View File
@@ -114,11 +114,14 @@ RendererServices::good(TextureHandle* texture_handle)
bool
RendererServices::is_udim(TextureHandle* texture_handle)
{
#if OPENIMAGEIO_VERSION >= 20307
return texturesys()->is_udim(texture_handle);
#else
return false;
#endif
}
bool
RendererServices::texture(ustring filename, TextureHandle* texture_handle,
TexturePerthread* texture_thread_info,
+28 -10
View File
@@ -3331,27 +3331,44 @@ RuntimeOptimizer::run()
OSL_DASSERT(sym1 && sym1->typespec().is_string());
if (sym1->is_constant()) {
if (op.nargs() == 3) {
Symbol* sym2 = opargsym(op, 2);
// getattribute( attributename, result )
m_attributes_needed.insert(
AttributeNeeded(sym1->get_string()));
} else {
OSL_DASSERT(op.nargs() == 4 || op.nargs() == 5);
AttributeNeeded(sym1->get_string(), ustring(),
sym2->typespec().simpletype()));
} else if (op.nargs() == 4) {
Symbol* sym2 = opargsym(op, 2);
Symbol* sym3 = opargsym(op, 3);
if (sym2->typespec().is_string()) {
// getattribute( scopename, attributename, result ) or
// getattribute( scopename, attributename, arrayindex, result )
// getattribute( scopename, attributename, result )
if (sym2->is_constant()) {
m_attributes_needed.insert(
AttributeNeeded(sym2->get_string(),
sym1->get_string()));
m_attributes_needed.insert(AttributeNeeded(
sym2->get_string(), sym1->get_string(),
sym3->typespec().simpletype()));
} else {
m_unknown_attributes_needed = true;
}
} else {
// getattribute( attributename, arrayindex, result )
m_attributes_needed.insert(
AttributeNeeded(sym1->get_string()));
AttributeNeeded(sym1->get_string(), ustring(),
sym3->typespec().simpletype()));
}
} else if (op.nargs() == 5) {
Symbol* sym2 = opargsym(op, 2);
Symbol* sym4 = opargsym(op, 4);
if (sym2->typespec().is_string()) {
// getattribute( scopename, attributename, arrayindex, result )
if (sym2->is_constant()) {
m_attributes_needed.insert(AttributeNeeded(
sym2->get_string(), sym1->get_string(),
sym4->typespec().simpletype()));
} else {
m_unknown_attributes_needed = true;
}
}
} else {
OSL_DASSERT(false);
}
} else { // sym1 not constant
m_unknown_attributes_needed = true;
@@ -3403,7 +3420,8 @@ RuntimeOptimizer::run()
if (m_attributes_needed.size()) {
shadingcontext()->infofmt("Group needs attributes:");
for (auto&& f : m_attributes_needed)
shadingcontext()->infofmt(" {} {}", f.name, f.scope);
shadingcontext()->infofmt(" {} {} {}", f.name, f.scope,
f.type);
if (m_unknown_attributes_needed)
shadingcontext()->infofmt(
" Also may construct attribute names on the fly.");
+1 -1
View File
@@ -481,7 +481,7 @@ private:
ShaderGlobals m_shaderglobals; ///< Dummy ShaderGlobals
// Keep track of some things for the whole shader group:
typedef std::unordered_map<ustring, ustring> ustringmap_t;
typedef std::unordered_map<ustring, ustring, ustringHash> ustringmap_t;
std::vector<ustringmap_t> m_params_holding_globals;
///< Which params of each layer really just hold globals
-26
View File
@@ -1,26 +0,0 @@
// Copyright Contributors to the Open Shading Language project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
#include "opcolor.h"
OSL_NAMESPACE_ENTER
namespace pvt {
// Intent is for a device to export or serialize the ShadingStateUniform from the
// ShadingSystem into a device side buffer that can be passed into
// kernel launches.
// Requires data to be self-contained and flat in memory to be device friendly.
struct ShadingStateUniform {
ColorSystem m_colorsystem; ///< Data for current colorspace
ustring m_commonspace_synonym; ///< Synonym for "common" space
bool m_unknown_coordsys_error; ///< Error to use unknown xform name?
};
} // namespace pvt
OSL_NAMESPACE_EXIT
+36 -21
View File
@@ -1002,6 +1002,7 @@ ShadingSystemImpl::ShadingSystemImpl(RendererServices* renderer,
, 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)
@@ -1048,6 +1049,7 @@ ShadingSystemImpl::ShadingSystemImpl(RendererServices* renderer,
, m_llvm_profiling_events(0)
, m_llvm_output_bitcode(0)
, m_llvm_dumpasm(0)
, m_commonspace_synonym("world")
, m_max_local_mem_KB(2048)
, m_compile_report(false)
, m_buffer_printf(true)
@@ -1069,9 +1071,6 @@ ShadingSystemImpl::ShadingSystemImpl(RendererServices* renderer,
, m_stat_inst_merge_time(0)
, m_stat_max_llvm_local_mem(0)
{
m_shading_state_uniform.m_commonspace_synonym = ustring("world");
m_shading_state_uniform.m_unknown_coordsys_error = true;
m_stat_shaders_loaded = 0;
m_stat_shaders_requested = 0;
m_stat_groups = 0;
@@ -1552,8 +1551,7 @@ ShadingSystemImpl::attribute(string_view name, TypeDesc type, const void* val)
ATTR_SET_STRING("llvm_prune_ir_strategy", m_llvm_prune_ir_strategy);
ATTR_SET("strict_messages", int, m_strict_messages);
ATTR_SET("range_checking", int, m_range_checking);
ATTR_SET("unknown_coordsys_error", int,
m_shading_state_uniform.m_unknown_coordsys_error);
ATTR_SET("unknown_coordsys_error", int, m_unknown_coordsys_error);
ATTR_SET("connection_error", int, m_connection_error);
ATTR_SET("greedyjit", int, m_greedyjit);
ATTR_SET("relaxed_param_typecheck", int, m_relaxed_param_typecheck);
@@ -1569,8 +1567,7 @@ ShadingSystemImpl::attribute(string_view name, TypeDesc type, const void* val)
ATTR_SET("exec_repeat", int, m_exec_repeat);
ATTR_SET("opt_warnings", int, m_opt_warnings);
ATTR_SET("gpu_opt_error", int, m_gpu_opt_error);
ATTR_SET_STRING("commonspace",
m_shading_state_uniform.m_commonspace_synonym);
ATTR_SET_STRING("commonspace", m_commonspace_synonym);
ATTR_SET_STRING("debug_groupname", m_debug_groupname);
ATTR_SET_STRING("debug_layername", m_debug_layername);
ATTR_SET_STRING("opt_layername", m_opt_layername);
@@ -1721,15 +1718,13 @@ ShadingSystemImpl::getattribute(string_view name, TypeDesc type, void* val)
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_shading_state_uniform.m_unknown_coordsys_error);
ATTR_DECODE("unknown_coordsys_error", int, m_unknown_coordsys_error);
ATTR_DECODE("connection_error", int, m_connection_error);
ATTR_DECODE("greedyjit", int, m_greedyjit);
ATTR_DECODE("countlayerexecs", int, m_countlayerexecs);
ATTR_DECODE("relaxed_param_typecheck", int, m_relaxed_param_typecheck);
ATTR_DECODE("max_warnings_per_thread", int, m_max_warnings_per_thread);
ATTR_DECODE_STRING("commonspace",
m_shading_state_uniform.m_commonspace_synonym);
ATTR_DECODE_STRING("commonspace", m_commonspace_synonym);
ATTR_DECODE_STRING("colorspace", m_colorspace);
ATTR_DECODE_STRING("debug_groupname", m_debug_groupname);
ATTR_DECODE_STRING("debug_layername", m_debug_layername);
@@ -1979,16 +1974,18 @@ ShadingSystemImpl::getattribute(ShaderGroup* group, string_view name,
return true;
}
if (name == "group_init_name" && type.basetype == TypeDesc::STRING) {
*(ustring*)val = ustring::fmtformat("__direct_callable__group_{}_init",
group->name());
*(ustring*)val
= ustring::fmtformat("__direct_callable__group_{}_{}_init",
group->name(), group->id());
return true;
}
if (name == "group_entry_name" && type.basetype == TypeDesc::STRING) {
int nlayers = group->nlayers();
ShaderInstance* inst = (*group)[nlayers - 1];
// This formulation mirrors OSOProcessorBase::layer_function_name()
*(ustring*)val = ustring::fmtformat("__direct_callable__{}_{}",
group->name(), inst->layername());
*(ustring*)val = ustring::fmtformat("__direct_callable__{}_{}_{}",
group->name(), inst->layername(),
inst->id());
return true;
}
if (name == "layer_osofiles" && type.basetype == TypeDesc::STRING) {
@@ -2105,6 +2102,11 @@ ShadingSystemImpl::getattribute(ShaderGroup* group, string_view name,
*(ustring**)val = n ? &group->m_attribute_scopes[0] : NULL;
return true;
}
if (name == "attribute_types" && type.basetype == TypeDesc::PTR) {
size_t n = group->m_attribute_types.size();
*(TypeDesc**)val = n ? &group->m_attribute_types[0] : NULL;
return true;
}
if (name == "unknown_attributes_needed" && type == TypeDesc::TypeInt) {
*(int*)val = (int)group->m_unknown_attributes_needed;
return true;
@@ -2125,6 +2127,10 @@ ShadingSystemImpl::getattribute(ShaderGroup* group, string_view name,
*(void**)val = n ? &group->m_userdata_init_vals[0] : NULL;
return true;
}
if (name == "llvm_groupdata_size" && type == TypeDesc::TypeInt) {
*(int*)val = (int)group->llvm_groupdata_size();
return true;
}
return false;
}
@@ -2386,14 +2392,14 @@ ShadingSystemImpl::getstats(int level) const
<< (int)(100.0f * m_stat_empty_groups / m_stat_groups_compiled)
<< "%)\n";
if (m_stat_instances_compiled > 0 || m_stat_groups_compiled > 0) {
print(out, " Optimized {} ops to {} ({:.1f}%)\n", m_stat_preopt_ops,
m_stat_postopt_ops,
print(out, " Optimized {} ops to {} ({:.1f}%)\n",
(int)m_stat_preopt_ops, (int)m_stat_postopt_ops,
100.0
* (double(m_stat_postopt_ops)
/ (std::max(1, (int)m_stat_preopt_ops))
- 1.0));
print(out, " Optimized {} symbols to {} ({:.1f}%)\n",
m_stat_preopt_syms, m_stat_postopt_syms,
(int)m_stat_preopt_syms, (int)m_stat_postopt_syms,
100.0
* (double(m_stat_postopt_syms)
/ (std::max(1, (int)m_stat_preopt_syms))
@@ -3182,7 +3188,9 @@ ShadingSystemImpl::ReParameter(ShaderGroup& group, string_view layername_,
}
// Check for mismatch versus previously-declared type
if (!equivalent(sym->typespec(), type))
if ((relaxed_param_typecheck() && !relaxed_equivalent(sym->typespec(), type))
|| (!relaxed_param_typecheck()
&& !relaxed_equivalent(sym->typespec(), type)))
return false;
// Can't change param value if the group has already been optimized,
@@ -3557,6 +3565,7 @@ ShadingSystemImpl::optimize_group(ShaderGroup& group, ShadingContext* ctx,
for (auto&& f : rop.m_attributes_needed) {
group.m_attributes_needed.push_back(f.name);
group.m_attribute_scopes.push_back(f.scope);
group.m_attribute_types.push_back(f.type);
}
group.m_optimized = true;
@@ -4159,7 +4168,8 @@ ShadingContext::ocio_transform(StringParam fromspace, StringParam tospace,
const float eps = 0.001f;
Color3 CC[3] = { C.val(), C.val() + eps * C.dx(),
C.val() + eps * C.dy() };
cp->apply((float*)&CC, 3, 1, 3, sizeof(float), sizeof(Color3), 0);
cp->apply((float*)&CC, 3, 1, 3, sizeof(float), sizeof(Color3),
3 * sizeof(Color3));
Cout.set(CC[0], (CC[1] - CC[0]) * (1.0f / eps),
(CC[2] - CC[0]) * (1.0f / eps));
return true;
@@ -4459,8 +4469,13 @@ osl_bind_interpolated_param(void* sg_, const void* name, long long type,
sg->context->incr_get_userdata_calls();
}
if (status == 2) {
int udata_size = (userdata_has_derivs ? 3 : 1) * TYPEDESC(type).size();
// If userdata was present, copy it to the shader variable
memcpy(symbol_data, userdata_data, symbol_data_size);
memcpy(symbol_data, userdata_data,
std::min(symbol_data_size, udata_size));
if (symbol_data_size > udata_size)
memset((char*)symbol_data + udata_size, 0,
symbol_data_size - udata_size);
return 1;
}
return 0; // no such user data
+21
View File
@@ -149,6 +149,27 @@ equivalent(const TypeSpec& a, const TypeSpec& b)
|| a.is_unsized_array() != b.is_unsized_array());
}
// Relaxed rules just look to see that the types are isomorphic to each other (ie: same number of base values)
// Note that:
// * basetypes must match exactly (int vs float vs string)
// * valuetype cannot be unsized (we must know the concrete number of values)
// * if paramtype is sized (or not an array) just check for the total number of entries
// * if paramtype is unsized (shader writer is flexible about how many values come in) -- make sure we are a multiple of the target type
// * allow a single float setting a vec3 (or equivalent)
bool
relaxed_equivalent(const TypeSpec& a, const TypeSpec& b)
{
const TypeDesc paramtype = a.simpletype();
const TypeDesc valuetype = b.simpletype();
return valuetype.basetype == paramtype.basetype
&& !valuetype.is_unsized_array()
&& ((!paramtype.is_unsized_array()
&& valuetype.basevalues() == paramtype.basevalues())
|| (paramtype.is_unsized_array()
&& valuetype.basevalues() % paramtype.aggregate == 0)
|| (paramtype.is_vec3() && valuetype == TypeDesc::FLOAT));
}
}; // namespace pvt
+4 -2
View File
@@ -90,8 +90,10 @@ abs(const Dual2<float>& x)
#define __OSL_XMACRO_ARGS (fabs, std::abs)
#include "wide_opunary_int_xmacro.h"
#define __OSL_XMACRO_ARGS (fmod, OIIO::safe_fmod)
#include "wide_opbinary_per_component_float_or_vector_xmacro.h"
#define __OSL_XMACRO_ARGS (fmod, OIIO::safe_fmod, safe_fmod)
#include "wide_opbinary_per_component_xmacro.h"
#define __OSL_XMACRO_ARGS (fmod, OIIO::safe_fmod, safe_fmod)
#include "wide_opbinary_per_component_mixed_vector_float_xmacro.h"
static OSL_FORCEINLINE float
+10 -10
View File
@@ -105,8 +105,8 @@ default_texture(BatchedRendererServices* bsr, ustring filename,
// It's actually faster to ask for 4 channels (even if we need fewer)
// and ensure that they're being put in aligned memory.
// TODO: investigate if the above statement is true when nchannels==1
// NOTE: using simd::float4 to speedup texture transformation below
OIIO::simd::float4 result_simd, dresultds_simd, dresultdt_simd;
// NOTE: using simd::vfloat4 to speedup texture transformation below
OIIO::simd::vfloat4 result_simd, dresultds_simd, dresultdt_simd;
bool retVal = false;
@@ -120,8 +120,8 @@ default_texture(BatchedRendererServices* bsr, ustring filename,
has_derivs ? (float*)&dresultds_simd : NULL,
has_derivs ? (float*)&dresultdt_simd : NULL);
OIIO::simd::float4 dresultdx_simd;
OIIO::simd::float4 dresultdy_simd;
OIIO::simd::vfloat4 dresultdx_simd;
OIIO::simd::vfloat4 dresultdy_simd;
if (has_derivs) {
// Correct our st texture space gradients into xy-space gradients
dresultdx_simd = dresultds_simd * dsdx + dresultdt_simd * dtdx;
@@ -297,8 +297,8 @@ default_texture3d(BatchedRendererServices* bsr, ustring filename,
// and ensure that they're being put in aligned memory.
// TODO: investigate if the above statement is true when nchannels==1
// NOTE: using simd::float4 to speedup texture transformation below
OIIO::simd::float4 result_simd, dresultds_simd, dresultdt_simd,
// NOTE: using simd::vfloat4 to speedup texture transformation below
OIIO::simd::vfloat4 result_simd, dresultds_simd, dresultdt_simd,
dresultdr_simd;
bool retVal = false;
@@ -314,8 +314,8 @@ default_texture3d(BatchedRendererServices* bsr, ustring filename,
has_derivs ? (float*)&dresultdt_simd : nullptr,
has_derivs ? (float*)&dresultdr_simd : nullptr);
OIIO::simd::float4 dresultdx_simd;
OIIO::simd::float4 dresultdy_simd;
OIIO::simd::vfloat4 dresultdx_simd;
OIIO::simd::vfloat4 dresultdy_simd;
if (has_derivs) {
// Correct our str texture space gradients into xyz-space gradients
dresultdx_simd = dresultds_simd * dPdx.x + dresultdt_simd * dPdx.y
@@ -480,8 +480,8 @@ default_environment(BatchedRendererServices* bsr, ustring filename,
// and ensure that they're being put in aligned memory.
// TODO: investigate if the above statement is true when nchannels==1
// NOTE: using simd::float4 to speedup texture transformation below
OIIO::simd::float4 result_simd;
// NOTE: using simd::vfloat4 to speedup texture transformation below
OIIO::simd::vfloat4 result_simd;
bool retVal = false;
+13 -2
View File
@@ -3,7 +3,7 @@
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
set (CMAKE_AUTOMOC ON)
if (Qt5_POSITION_INDEPENDENT_CODE)
if (Qt5_POSITION_INDEPENDENT_CODE OR Qt6_POSITION_INDEPENDENT_CODE)
set (CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
set (osltoy_srcs
@@ -13,6 +13,17 @@ set_target_properties (osltoy PROPERTIES FOLDER "Tools")
target_link_libraries (osltoy
PRIVATE
oslexec
Qt5::Core Qt5::Gui Qt5::Widgets
$<TARGET_NAME_IF_EXISTS:Qt5::Core>
$<TARGET_NAME_IF_EXISTS:Qt5::Gui>
$<TARGET_NAME_IF_EXISTS:Qt5::Widgets>
$<TARGET_NAME_IF_EXISTS:Qt6::Core>
$<TARGET_NAME_IF_EXISTS:Qt6::Gui>
$<TARGET_NAME_IF_EXISTS:Qt6::Widgets>
${Boost_LIBRARIES} ${CMAKE_DL_LIBS})
if (Qt5_FOUND)
target_compile_definitions(osltoy PRIVATE OSL_QT_MAJOR=5)
endif ()
if (Qt6_FOUND)
target_compile_definitions(osltoy PRIVATE OSL_QT_MAJOR=6)
endif ()
install_targets (osltoy)
+12
View File
@@ -198,7 +198,11 @@ public:
QWidget::hideEvent(e);
}
#if OSL_QT_MAJOR < 6
void enterEvent(QEvent* event) override;
#else
void enterEvent(QEnterEvent* event) override;
#endif
void mouseMoveEvent(QMouseEvent* event) override;
};
@@ -293,7 +297,11 @@ public:
void mouseMoveEvent(QMouseEvent* /*event*/) override { magnifierEvent(); }
#if OSL_QT_MAJOR < 6
void enterEvent(QEvent* /*event*/) override
#else
void enterEvent(QEnterEvent* /*event*/) override
#endif
{
if (shouldShowMagnifier())
showMagnifier();
@@ -343,7 +351,11 @@ public:
};
void
#if OSL_QT_MAJOR < 6
Magnifier::enterEvent(QEvent* event)
#else
Magnifier::enterEvent(QEnterEvent* event)
#endif
{
if (m_renderview)
m_renderview->magnifierEvent();
+4
View File
@@ -16,6 +16,10 @@
#include <OSL/oslquery.h>
#include <OSL/rendererservices.h>
#ifndef OSL_QT_MAJOR
# error "Build problem? OSL_QT_MAJOR not defined."
#endif
#include <QAction>
#include <QMainWindow>
#include <QTimer>
+1 -1
View File
@@ -115,7 +115,7 @@ private:
typedef bool (OSLToyRenderer::*AttrGetter)(ShaderGlobals* sg, bool derivs,
ustring object, TypeDesc type,
ustring name, void* val);
typedef std::unordered_map<ustring, AttrGetter> AttrGetterMap;
typedef std::unordered_map<ustring, AttrGetter, ustringHash> AttrGetterMap;
AttrGetterMap m_attr_getters;
// Attribute getters
+10 -20
View File
@@ -16,30 +16,20 @@ glass
float eta = 1.5
[[ string help = "Index of refraction",
float min = 1, float max = 3 ]],
int caustics = 0
[[ string help = "Enable indirect lighting through glass",
string widget = "checkBox" ]],
int TIR = 0
[[ string help = "Enable Total Internal Reflection",
string widget = "checkBox" ]]
)
{
// If the current ray type is glossy or diffuse, that means we
// are computing indirect lighting. Letting that interact with
// glass produces caustics, which are normally hard to trace and
// noisy. So we only return closures if that's not the case or
// the "caustics" flag is on.
if (caustics || (!raytype("glossy") && !raytype("diffuse"))) {
// Take into account backfacing to invert eta accordingly
if (backfacing()) {
Ci = Cs * refraction(N, 1.0 / eta);
// If Total Internal Reflection is enabled, we also return a
// reflection closure, which might make rays bounce too much
// inside an object. That's why we make it optional.
if (TIR)
Ci += Ks * reflection(N, 1.0 / eta);
} else {
Ci = Ks * reflection(N, eta) + Cs * refraction(N, eta);
}
// Take into account backfacing to invert eta accordingly
if (backfacing()) {
Ci = Cs * refraction(N, 1.0 / eta);
// If Total Internal Reflection is enabled, we also return a
// reflection closure, which might make rays bounce too much
// inside an object. That's why we make it optional.
if (TIR)
Ci += Ks * reflection(N, 1.0 / eta);
} else {
Ci = Ks * reflection(N, eta) + Cs * refraction(N, eta);
}
}
+9 -7
View File
@@ -3,19 +3,21 @@
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
# The 'testrender' executable
set (testrender_srcs
shading.cpp
simpleraytracer.cpp
testrender.cpp)
file(GLOB testrender_srcs *.cpp)
if (USE_OPTIX)
list (APPEND testrender_srcs optixraytracer.cpp)
set (testrender_cuda_srcs
cuda/quad.cu
cuda/optix_raytracer.cu
cuda/sphere.cu
cuda/wrapper.cu
cuda/rend_lib.cu)
cuda/wrapper.cu )
# We only need to generate the PTX for rend_lib.cu if we are using OptiX 7.0+.
# Some of OptiX 6 device functions defined in rend_lib.cu cannot be compiled
# with NVCC, they must be compiled with clang using the LLVM_COMPILE_CUDA macro.
if (OPTIX_VERSION VERSION_GREATER_EQUAL 7)
list (APPEND testshade_cuda_srcs cuda/rend_lib.cu)
endif ()
# We need to make sure that the PTX files are regenerated whenever these
# headers change.
+88 -4
View File
@@ -5,14 +5,96 @@
#include <optix.h>
#if (OPTIX_VERSION < 70000)
# include <optixu/optixu_math_namespace.h>
# include <optixu/optixu_vector_types.h>
#endif
#include "util.h"
#include <optix_device.h>
#if (OPTIX_VERSION < 70000)
using namespace optix;
#include <OSL/device_string.h>
// Launch variables
rtDeclareVariable(uint2, launch_index, rtLaunchIndex, );
rtDeclareVariable(uint2, launch_dim, rtLaunchDim, );
#include "rend_lib.h"
#include "render_params.h"
// Scene/Shading variables
rtDeclareVariable(float3, bad_color, , );
rtDeclareVariable(float3, bg_color, , );
rtDeclareVariable(rtObject, top_object, , );
// Ray payload
rtDeclareVariable(PRD_radiance, prd_radiance, rtPayload, );
// Geometry/Intersection attributes
rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, );
rtDeclareVariable(float3, shading_normal, attribute shading_normal, );
// Camera variables
rtDeclareVariable(float3, eye, , );
rtDeclareVariable(float3, dir, , );
rtDeclareVariable(float3, cx, , );
rtDeclareVariable(float3, cy, , );
rtDeclareVariable(float, invw, , );
rtDeclareVariable(float, invh, , );
// Buffers
rtBuffer<float3, 2> output_buffer;
RT_PROGRAM void
raygen()
{
// Compute the pixel coordinates
float2 d = make_float2(static_cast<float>(launch_index.x) + 0.5f,
static_cast<float>(launch_index.y) + 0.5f);
// Make the ray for the current pixel
RayGeometry r;
r.origin = eye;
r.direction = optix::normalize(cx * (d.x * invw - 0.5f)
+ cy * (0.5f - d.y * invh) + dir);
Ray ray = optix::make_Ray(r.origin, r.direction, 0, 1e-3f, RT_DEFAULT_MAX);
// Create a struct to hold the shading result
PRD_radiance prd;
prd.result = make_float3(0.0f);
// Trace the ray against the scene. The hit/miss program is called before
// this call returns.
rtTrace(top_object, ray, prd);
// Write the shading result to the output buffer
output_buffer[launch_index] = prd.result;
}
RT_PROGRAM void
miss()
{
prd_radiance.result = bg_color;
}
RT_PROGRAM void
exception()
{
rtPrintExceptionDetails();
output_buffer[launch_index] = bad_color;
}
#else //#if (OPTIX_VERSION < 70000)
# include <optix.h>
# include <optix_device.h>
# include <OSL/device_string.h>
# include "rend_lib.h"
# include "render_params.h"
extern "C" {
@@ -93,3 +175,5 @@ osl_tex2DLookup(void* handle, float s, float t)
cudaTextureObject_t texID = cudaTextureObject_t(handle);
return tex2D<float4>(texID, s, t);
}
#endif //#if (OPTIX_VERSION < 70000)
+76 -3
View File
@@ -5,11 +5,82 @@
#include <optix.h>
#include "rend_lib.h"
#include "render_params.h"
#include "wrapper.h"
#if (OPTIX_VERSION < 70000)
# include <optixu/optixu_aabb_namespace.h>
# include <optixu/optixu_math_namespace.h>
# include <optixu/optixu_vector_types.h>
using namespace optix;
rtDeclareVariable(float3, p, , );
rtDeclareVariable(float3, ex, , );
rtDeclareVariable(float3, ey, , );
rtDeclareVariable(float3, n, , );
rtDeclareVariable(float, eu, , );
rtDeclareVariable(float, ev, , );
rtDeclareVariable(float, a, , );
rtDeclareVariable(float3, texcoord, attribute texcoord, );
rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, );
rtDeclareVariable(float3, shading_normal, attribute shading_normal, );
rtDeclareVariable(float, surface_area, attribute surface_area, );
rtDeclareVariable(float3, dPdu, attribute dPdu, );
rtDeclareVariable(float3, dPdv, attribute dPdv, );
rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
RT_PROGRAM void
intersect(void)
{
float dn = dot(ray.direction, n);
float en = dot(p - ray.origin, n);
if (dn * en > 0) {
float t = en / dn;
float3 h = (ray.origin + ray.direction * t) - p;
float dx = dot(h, ex) * eu;
float dy = dot(h, ey) * ev;
if (dx >= 0 && dx < 1.0f && dy >= 0 && dy < 1.0f
&& rtPotentialIntersection(t)) {
shading_normal = geometric_normal = n;
texcoord = make_float3(dot(h, ex) * eu, dot(h, ey) * ev, 0.0f);
dPdu = ey;
dPdv = ex;
surface_area = a;
rtReportIntersection(0);
}
}
}
RT_PROGRAM void
bounds(int, float result[6])
{
const float3 p00 = p;
const float3 p01 = p + ex;
const float3 p10 = p + ey;
const float3 p11 = p + ex + ey;
const float area = length(cross(ex, ey));
optix::Aabb* aabb = reinterpret_cast<optix::Aabb*>(result);
if (area > 0.0f && !isinf(area)) {
aabb->m_min = fminf(fminf(p00, p01), fminf(p10, p11));
aabb->m_max = fmaxf(fmaxf(p00, p01), fmaxf(p10, p11));
} else {
aabb->invalidate();
}
}
#else //#if (OPTIX_VERSION < 70000)
# include "rend_lib.h"
# include "render_params.h"
# include "wrapper.h"
extern "C" __device__ void
__direct_callable__quad_shaderglobals(const unsigned int idx, const float t_hit,
const float3 ray_origin,
@@ -60,3 +131,5 @@ __intersection__quad()
optixReportIntersection(t, RAYTRACER_HIT_QUAD);
}
}
#endif //#if (OPTIX_VERSION < 70000)
+475 -15
View File
@@ -4,15 +4,473 @@
#include <optix.h>
#include <optix_device.h>
#define OPTIX_COMPATIBILITY 7
#if (OPTIX_VERSION < 70000)
# include <optix_math.h>
# include <optixu/optixu_matrix_namespace.h>
#else
# define OPTIX_COMPATIBILITY 7
# include <cuda_runtime.h>
# include <optix_device.h>
#endif
#include <OSL/oslclosure.h>
#include <cuda_runtime.h>
#include <optix_device.h>
#include "rend_lib.h"
#if (OPTIX_VERSION < 70000)
rtDeclareVariable(uint2, launch_index, rtLaunchIndex, );
rtDeclareVariable(uint2, launch_dim, rtLaunchDim, );
rtDeclareVariable(char*, test_str_1, , );
rtDeclareVariable(char*, test_str_2, , );
// N.B. These will be cast to OSL::Matrix44 variables when used.
rtDeclareVariable(optix::Matrix4x4, object2common, , );
rtDeclareVariable(optix::Matrix4x4, shader2common, , );
rtBuffer<uint64_t> xform_name_buffer;
rtBuffer<optix::Matrix4x4> xform_buffer;
OSL_NAMESPACE_ENTER
namespace pvt {
rtBuffer<char, 1> s_color_system;
}
OSL_NAMESPACE_EXIT
// Taken from the SimplePool class
__device__ static inline size_t
alignment_offset_calc(void* ptr, size_t alignment)
{
uintptr_t ptrbits = reinterpret_cast<uintptr_t>(ptr);
uintptr_t offset = ((ptrbits + alignment - 1) & -alignment) - ptrbits;
return offset;
}
// These functions are declared extern to prevent name mangling.
extern "C" {
__device__ void*
closure_component_allot(void* pool, int id, size_t prim_size,
const OSL::Color3& w)
{
((OSL::ClosureComponent*)pool)->id = id;
((OSL::ClosureComponent*)pool)->w = w;
size_t needed = (sizeof(OSL::ClosureComponent) - sizeof(void*) + prim_size
+ (alignof(OSL::ClosureComponent) - 1))
& ~(alignof(OSL::ClosureComponent) - 1);
char* char_ptr = (char*)pool;
return (void*)&char_ptr[needed];
}
__device__ void*
closure_mul_allot(void* pool, const OSL::Color3& w, OSL::ClosureColor* c)
{
((OSL::ClosureMul*)pool)->id = OSL::ClosureColor::MUL;
((OSL::ClosureMul*)pool)->weight = w;
((OSL::ClosureMul*)pool)->closure = c;
size_t needed = (sizeof(OSL::ClosureMul)
+ (alignof(OSL::ClosureComponent) - 1))
& ~(alignof(OSL::ClosureComponent) - 1);
char* char_ptr = (char*)pool;
return &char_ptr[needed];
}
__device__ void*
closure_mul_float_allot(void* pool, const float& w, OSL::ClosureColor* c)
{
((OSL::ClosureMul*)pool)->id = OSL::ClosureColor::MUL;
((OSL::ClosureMul*)pool)->weight.x = w;
((OSL::ClosureMul*)pool)->weight.y = w;
((OSL::ClosureMul*)pool)->weight.z = w;
((OSL::ClosureMul*)pool)->closure = c;
size_t needed = (sizeof(OSL::ClosureMul)
+ (alignof(OSL::ClosureComponent) - 1))
& ~(alignof(OSL::ClosureComponent) - 1);
char* char_ptr = (char*)pool;
return &char_ptr[needed];
}
__device__ void*
closure_add_allot(void* pool, OSL::ClosureColor* a, OSL::ClosureColor* b)
{
((OSL::ClosureAdd*)pool)->id = OSL::ClosureColor::ADD;
((OSL::ClosureAdd*)pool)->closureA = a;
((OSL::ClosureAdd*)pool)->closureB = b;
size_t needed = (sizeof(OSL::ClosureAdd)
+ (alignof(OSL::ClosureComponent) - 1))
& ~(alignof(OSL::ClosureComponent) - 1);
char* char_ptr = (char*)pool;
return &char_ptr[needed];
}
__device__ void*
osl_allocate_closure_component(void* sg_, int id, int size)
{
ShaderGlobals* sg_ptr = (ShaderGlobals*)sg_;
OSL::Color3 w = OSL::Color3(1, 1, 1);
// Fix up the alignment
void* ret = ((char*)sg_ptr->renderstate)
+ alignment_offset_calc(sg_ptr->renderstate,
alignof(OSL::ClosureComponent));
size = max(4, size);
sg_ptr->renderstate = closure_component_allot(ret, id, size, w);
return ret;
}
__device__ void*
osl_allocate_weighted_closure_component(void* sg_, int id, int size,
const OSL::Color3* w)
{
ShaderGlobals* sg_ptr = (ShaderGlobals*)sg_;
if (w->x == 0.0f && w->y == 0.0f && w->z == 0.0f) {
return NULL;
}
size = max(4, size);
// Fix up the alignment
void* ret = ((char*)sg_ptr->renderstate)
+ alignment_offset_calc(sg_ptr->renderstate,
alignof(OSL::ClosureComponent));
sg_ptr->renderstate = closure_component_allot(ret, id, size, *w);
return ret;
}
__device__ void*
osl_mul_closure_color(void* sg_, OSL::ClosureColor* a, const OSL::Color3* w)
{
ShaderGlobals* sg_ptr = (ShaderGlobals*)sg_;
if (a == NULL) {
return NULL;
}
if (w->x == 0.0f && w->y == 0.0f && w->z == 0.0f) {
return NULL;
}
if (w->x == 1.0f && w->y == 1.0f && w->z == 1.0f) {
return a;
}
// Fix up the alignment
void* ret = ((char*)sg_ptr->renderstate)
+ alignment_offset_calc(sg_ptr->renderstate,
alignof(OSL::ClosureComponent));
sg_ptr->renderstate = closure_mul_allot(ret, *w, a);
return ret;
}
__device__ void*
osl_mul_closure_float(void* sg_, OSL::ClosureColor* a, float w)
{
ShaderGlobals* sg_ptr = (ShaderGlobals*)sg_;
if (a == NULL || w == 0.0f) {
return NULL;
}
if (w == 1.0f) {
return a;
}
// Fix up the alignment
void* ret = ((char*)sg_ptr->renderstate)
+ alignment_offset_calc(sg_ptr->renderstate,
alignof(OSL::ClosureComponent));
sg_ptr->renderstate = closure_mul_float_allot(ret, w, a);
return ret;
}
__device__ void*
osl_add_closure_closure(void* sg_, OSL::ClosureColor* a, OSL::ClosureColor* b)
{
ShaderGlobals* sg_ptr = (ShaderGlobals*)sg_;
if (a == NULL) {
return b;
}
if (b == NULL) {
return a;
}
// Fix up the alignment
void* ret = ((char*)sg_ptr->renderstate)
+ alignment_offset_calc(sg_ptr->renderstate,
alignof(OSL::ClosureComponent));
sg_ptr->renderstate = closure_add_allot(ret, a, b);
return ret;
}
# define IS_STRING(type) (type.basetype == OSL::TypeDesc::STRING)
# define IS_PTR(type) (type.basetype == OSL::TypeDesc::PTR)
# define IS_COLOR(type) (type.vecsemantics == OSL::TypeDesc::COLOR)
__device__ bool
rend_get_userdata(OSL::StringParam name, void* data, int data_size,
const OSL::TypeDesc& type, int index)
{
// Perform a userdata lookup using the parameter name, type, and
// userdata index. If there is a match, memcpy the value into data and
// return 1.
if (IS_PTR(type) && name == STRING_PARAMS(colorsystem)) {
*(void**)data = &OSL::pvt::s_color_system[0];
return true;
}
// TODO: This is temporary code for initial testing and demonstration.
if (IS_STRING(type) && name == HDSTR(test_str_1)) {
memcpy(data, &test_str_2, 8);
return true;
}
return false;
}
# undef IS_COLOR
# undef IS_STRING
# undef IS_PTR
__device__ int
osl_bind_interpolated_param(void* sg_, const void* name, long long type,
int userdata_has_derivs, void* userdata_data,
int symbol_has_derivs, void* symbol_data,
int symbol_data_size, char* userdata_initialized,
int userdata_index)
{
char status = *userdata_initialized;
if (status == 0) {
bool ok = rend_get_userdata(HDSTR(name), userdata_data,
symbol_data_size, (*(OSL::TypeDesc*)&type),
userdata_index);
*userdata_initialized = status = 1 + ok;
}
if (status == 2) {
memcpy(symbol_data, userdata_data, symbol_data_size);
return 1;
}
return 0;
}
__device__ int
osl_strlen_is(const char* str)
{
return HDSTR(str).length();
}
__device__ int
osl_hash_is(const char* str)
{
return HDSTR(str).hash();
}
__device__ int
osl_getchar_isi(const char* str, int index)
{
return (str && unsigned(index) < HDSTR(str).length()) ? str[index] : 0;
}
__device__ void
osl_printf(void* sg_, char* fmt_str, void* args)
{
// This can be used to limit printing to one Cuda thread for debugging
// if (launch_index.x == 0 && launch_index.y == 0)
//
vprintf(fmt_str, (const char*)args);
}
__device__ void*
osl_get_noise_options(void* sg_)
{
ShaderGlobals* sg = ((ShaderGlobals*)sg_);
NoiseOptCUDA* opt
= (NoiseOptCUDA*)((ShadingContextCUDA*)sg->context)->noise_options_ptr();
new (opt) NoiseOptCUDA;
return opt;
}
__device__ void*
osl_get_texture_options(void* sg_)
{
return 0;
}
__device__ void
osl_texture_set_interp_code(void* opt, int mode)
{
// ((TextureOpt *)opt)->interpmode = (TextureOpt::InterpMode)mode;
}
__device__ void
osl_texture_set_stwrap_code(void* opt, int mode)
{
//((TextureOpt *)opt)->swrap = (TextureOpt::Wrap)mode;
//((TextureOpt *)opt)->twrap = (TextureOpt::Wrap)mode;
}
__device__ int
osl_texture(void* sg_, const char* name, void* handle, void* opt_, float s,
float t, float dsdx, float dtdx, float dsdy, float dtdy, int chans,
void* result, void* dresultdx, void* dresultdy, void* alpha,
void* dalphadx, void* dalphady, void* ustring_errormessage)
{
if (!handle)
return 0;
int64_t texID = int64_t(handle);
*((float3*)result) = make_float3(optix::rtTex2D<float4>(texID, s, t));
return 1;
}
__device__ int
osl_range_check_err(int indexvalue, int length, const char* symname, void* sg,
const void* sourcefile, int sourceline,
const char* groupname, int layer, const char* layername,
const char* shadername)
{
if (indexvalue < 0 || indexvalue >= length) {
return indexvalue < 0 ? 0 : length - 1;
}
return indexvalue;
}
__device__ int
osl_range_check(int indexvalue, int length, const char* symname, void* sg,
const void* sourcefile, int sourceline, const char* groupname,
int layer, const char* layername, const char* shadername)
{
if (indexvalue < 0 || indexvalue >= length) {
indexvalue = osl_range_check_err(indexvalue, length, symname, sg,
sourcefile, sourceline, groupname,
layer, layername, shadername);
}
return indexvalue;
}
# define MAT(m) (*(OSL::Matrix44*)m)
__device__ int
osl_get_matrix(void* sg_, void* r, const char* from)
{
ShaderGlobals* sg = (ShaderGlobals*)sg_;
if (HDSTR(from) == STRING_PARAMS(common)) {
MAT(r).makeIdentity();
return true;
}
if (HDSTR(from) == STRING_PARAMS(object)) {
MAT(r) = MAT(&object2common);
return true;
}
if (HDSTR(from) == STRING_PARAMS(shader)) {
MAT(r) = MAT(&shader2common);
return true;
}
// Find the index of the named transform in the transform list
int match_idx = -1;
for (size_t idx = 0; idx < xform_name_buffer.size(); ++idx) {
if (HDSTR(from) == HDSTR(xform_name_buffer[idx])) {
match_idx = static_cast<int>(idx);
break;
}
}
// Return the transform if there is a match
if (match_idx >= 0) {
MAT(r) = MAT(&xform_buffer[match_idx]);
return true;
}
int ok = false; // TODO: Implement transform
if (!ok) {
MAT(r).makeIdentity();
// TBR: OSL would throw an error here, what should we do?
}
return ok;
}
__device__ int
osl_get_inverse_matrix(void* sg_, void* r, const char* to)
{
ShaderGlobals* sg = (ShaderGlobals*)sg_;
if (HDSTR(to) == STRING_PARAMS(common)) {
MAT(r).makeIdentity();
return true;
}
if (HDSTR(to) == STRING_PARAMS(object)) {
MAT(r) = MAT(&object2common);
MAT(r).invert();
return true;
}
if (HDSTR(to) == STRING_PARAMS(shader)) {
MAT(r) = MAT(&shader2common);
MAT(r).invert();
return true;
}
// Find the index of the named transform in the transform list
int match_idx = -1;
for (size_t idx = 0; idx < xform_name_buffer.size(); ++idx) {
if (HDSTR(to) == HDSTR(xform_name_buffer[idx])) {
match_idx = static_cast<int>(idx);
break;
}
}
// Return the transform if there is a match
if (match_idx >= 0) {
MAT(r) = MAT(&xform_buffer[match_idx]);
MAT(r).invert();
return true;
}
int ok = false; // TODO: Implement transform
if (!ok) {
MAT(r).makeIdentity();
// TBR: OSL would throw an error here, what should we do?
}
return ok;
}
# undef MAT
}
#else //#if (OPTIX_VERSION < 70000)
OSL_NAMESPACE_ENTER
@@ -232,9 +690,9 @@ osl_add_closure_closure(void* sg_, OSL::ClosureColor* a, OSL::ClosureColor* b)
}
#define IS_STRING(type) (type.basetype == OSL::TypeDesc::STRING)
#define IS_PTR(type) (type.basetype == OSL::TypeDesc::PTR)
#define IS_COLOR(type) (type.vecsemantics == OSL::TypeDesc::COLOR)
# define IS_STRING(type) (type.basetype == OSL::TypeDesc::STRING)
# define IS_PTR(type) (type.basetype == OSL::TypeDesc::PTR)
# define IS_COLOR(type) (type.vecsemantics == OSL::TypeDesc::COLOR)
__device__ bool
@@ -258,9 +716,9 @@ rend_get_userdata(OSL::StringParam name, void* data, int data_size,
return false;
}
#undef IS_COLOR
#undef IS_STRING
#undef IS_PTR
# undef IS_COLOR
# undef IS_STRING
# undef IS_PTR
@@ -399,8 +857,8 @@ osl_texture(void* sg_, const char* name, void* handle, void* opt_, float s,
{
if (!handle)
return 0;
// cudaTextureObject_t texID = cudaTextureObject_t(handle);
float4 fromTexture = osl_tex2DLookup(handle, s, t);
cudaTextureObject_t texID = cudaTextureObject_t(handle);
float4 fromTexture = osl_tex2DLookup(handle, s, t);
// see note above
// float4 fromTexture = tex2D<float4>(texID, s, t);
*((float3*)result) = make_float3(fromTexture.x, fromTexture.y,
@@ -439,7 +897,7 @@ osl_range_check(int indexvalue, int length, const char* symname, void* sg,
#define MAT(m) (*(OSL::Matrix44*)m)
# define MAT(m) (*(OSL::Matrix44*)m)
__device__ int
osl_get_matrix(void* sg_, void* r, const char* from)
@@ -528,5 +986,7 @@ osl_get_inverse_matrix(void* sg_, void* r, const char* to)
return ok;
}
#undef MAT
# undef MAT
}
#endif //#if (OPTIX_VERSION < 70000)
+25 -9
View File
@@ -4,24 +4,34 @@
#pragma once
#include "../../liboslexec/string_hash.h"
#include <OSL/oslexec.h>
#if (OPTIX_VERSION < 70000)
# include <optix_math.h>
#else
# include "../../liboslexec/string_hash.h"
# include <OSL/oslexec.h>
#endif
#include <OSL/device_string.h>
OSL_NAMESPACE_ENTER
// Create an OptiX variable for each of the 'standard' strings declared in
// <OSL/strdecls.h>.
namespace DeviceStrings {
#define STRING_PARAMS(x) UStringHash::Hash(__OSL_STRINGIFY(x))
#if OPTIX_VERSION < 70000
# define STRDECL(str, var_name) \
rtDeclareVariable(OSL_NAMESPACE::DeviceString, var_name, , );
# define STRING_PARAMS(x) StringParams::x
#else
# define STRING_PARAMS(x) UStringHash::Hash(__OSL_STRINGIFY(x))
// Don't declare anything
#define STRDECL(str, var_name)
# define STRDECL(str, var_name)
#endif
#include <OSL/strdecls.h>
#undef STRDECL
} // namespace DeviceStrings
#if OPTIX_VERSION >= 70000
namespace pvt {
extern __device__ CUdeviceptr s_color_system;
extern __device__ CUdeviceptr osl_printf_buffer_start;
@@ -32,11 +42,17 @@ extern __device__ uint64_t num_named_xforms;
extern __device__ CUdeviceptr xform_name_buffer;
extern __device__ CUdeviceptr xform_buffer;
} // namespace pvt
#endif
OSL_NAMESPACE_EXIT
namespace { // anonymous namespace
#if (OPTIX_VERSION < 70000)
# ifdef __cplusplus
typedef optix::float3 float3;
# endif
#endif
// These are CUDA variants of various OSL options structs. Their layouts and
// default values are identical to the host versions, but they might differ in
// how they are constructed. They are duplicated here as a convenience and to
@@ -98,7 +114,6 @@ struct ShaderGlobals {
float3 dPdtime;
float3 Ps, dPsdx, dPsdy;
void* renderstate;
void* shadingStateUniform;
void* tracedata;
void* objdata;
void* context;
@@ -144,7 +159,7 @@ enum ClosureIDs {
HOLDOUT_ID,
};
#if (OPTIX_VERSION >= 70000)
// ========================================
//
// Some helper vector functions
@@ -193,5 +208,6 @@ normalize(const float3& v)
}
//
// ========================================
#endif //#if (OPTIX_VERSION >= 70000)
} // anonymous namespace
+123 -3
View File
@@ -5,10 +5,128 @@
#include <optix.h>
#if (OPTIX_VERSION < 70000)
# include <optixu/optixu_aabb_namespace.h>
# include <optixu/optixu_math_namespace.h>
# include <optixu/optixu_vector_types.h>
#include "rend_lib.h"
#include "render_params.h"
#include "wrapper.h"
# include <OSL/dual.h>
# include <OSL/dual_vec.h>
# include <OSL/oslconfig.h>
# include <OSL/shaderglobals.h>
# include <OpenImageIO/fmath.h>
using namespace optix;
using OSL::Dual2;
using OSL::Vec3;
rtDeclareVariable(float4, sphere, , );
rtDeclareVariable(float, r2, , );
rtDeclareVariable(float, a, , );
rtDeclareVariable(float3, texcoord, attribute texcoord, );
rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, );
rtDeclareVariable(float3, shading_normal, attribute shading_normal, );
rtDeclareVariable(float, surface_area, attribute surface_area, );
rtDeclareVariable(float3, dPdu, attribute dPdu, );
rtDeclareVariable(float3, dPdv, attribute dPdv, );
rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
static __device__ __inline__ void
calc_uv()
{
Dual2<Vec3> n(Vec3(shading_normal.x, shading_normal.y, shading_normal.z));
Dual2<float> nx(n.val().x, n.dx().x, n.dy().x);
Dual2<float> ny(n.val().y, n.dx().y, n.dy().y);
Dual2<float> nz(n.val().z, n.dx().z, n.dy().z);
Dual2<float> u = (fast_atan2(nx, nz) + Dual2<float>(M_PI)) * 0.5f
* float(M_1_PI);
Dual2<float> v = fast_acos(ny) * float(M_1_PI);
float xz2 = nx.val() * nx.val() + nz.val() * nz.val();
if (xz2 > 0.0f) {
const float PI = float(M_PI);
const float TWOPI = float(2 * M_PI);
float xz = sqrtf(xz2);
float inv = 1.0f / xz;
dPdu.x = -TWOPI * nx.val();
dPdu.y = TWOPI * nz.val();
dPdu.z = 0.0f;
dPdv.x = -PI * nz.val() * inv * ny.val();
dPdv.y = -PI * nx.val() * inv * ny.val();
dPdv.z = PI * xz;
} else {
// pick arbitrary axes for poles to avoid division by 0
if (ny.val() > 0.0f) {
dPdu = make_float3(0.0f, 0.0f, 1.0f);
dPdv = make_float3(1.0f, 0.0f, 0.0f);
} else {
dPdu = make_float3(0.0f, 0.0f, 1.0f);
dPdv = make_float3(-1.0f, 0.0f, 0.0f);
}
}
texcoord = make_float3(u.val(), v.val(), 0.0f);
}
// Intersection adapted from testrender/raytracer.h
RT_PROGRAM void
intersect(void)
{
float3 c = make_float3(sphere);
float3 oc = c - ray.origin;
float b = dot(oc, ray.direction);
float det = b * b - dot(oc, oc) + r2;
if (det >= 0.0f) {
det = sqrtf(det);
float x = b - det;
float y = b + det;
// NB: this does not included the 'self' check from
// the testrender sphere intersection
float t = (x > 0) ? x : ((y > 0) ? y : 0);
if (rtPotentialIntersection(t)) {
float3 P = ray.origin + ray.direction * t;
float3 N = normalize(P - c);
shading_normal = geometric_normal = N;
surface_area = a;
// Calculate the texture coordinates and derivatives
calc_uv();
rtReportIntersection(0);
}
}
}
RT_PROGRAM void
bounds(int, float result[6])
{
const float3 center = make_float3(sphere);
const float3 radius = make_float3(sphere.w);
optix::Aabb* aabb = reinterpret_cast<optix::Aabb*>(result);
if (radius.x > 0.0f && !isinf(radius.x)) {
aabb->m_min = center - radius;
aabb->m_max = center + radius;
} else {
aabb->invalidate();
}
}
#else //#if (OPTIX_VERSION < 70000)
# include "rend_lib.h"
# include "render_params.h"
# include "wrapper.h"
static __device__ __inline__ void
@@ -94,3 +212,5 @@ __intersection__sphere()
optixReportIntersection(t, RAYTRACER_HIT_SPHERE);
}
}
#endif //#if (OPTIX_VERSION < 70000)
+7
View File
@@ -7,6 +7,13 @@
#include <optix.h>
#if (OPTIX_VERSION < 70000)
# include <optixu/optixu_math_namespace.h>
# include <optixu/optixu_vector_types.h>
typedef optix::float3 float3;
typedef optix::uchar4 uchar4;
#endif
#include <stdint.h>
+196 -3
View File
@@ -5,8 +5,12 @@
#include <optix.h>
#include <cuda_runtime.h>
#include <optix.h>
#if (OPTIX_VERSION < 70000)
# include <optixu/optixu_math_namespace.h>
#else
# include <cuda_runtime.h>
# include <optix.h>
#endif
#include <OSL/device_string.h>
#include <OSL/oslclosure.h>
@@ -14,7 +18,194 @@
#include "rend_lib.h"
#include "util.h"
#include "../render_params.h"
#if (OPTIX_VERSION < 70000)
// Ray payload
rtDeclareVariable(PRD_radiance, prd_radiance, rtPayload, );
// ray/hit variables
rtDeclareVariable(float3, shading_normal, attribute shading_normal, );
rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, );
rtDeclareVariable(float3, texcoord, attribute texcoord, );
rtDeclareVariable(float, surface_area, attribute surface_area, );
rtDeclareVariable(float3, dPdu, attribute dPdu, );
rtDeclareVariable(float3, dPdv, attribute dPdv, );
rtDeclareVariable(int, obj_id, attribute obj_id, );
rtDeclareVariable(int, lgt_idx, attribute lgt_idx, );
// ray/hit variables
rtDeclareVariable(uint2, launch_index, rtLaunchIndex, );
rtDeclareVariable(uint2, launch_dim, rtLaunchDim, );
rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
rtDeclareVariable(float, t_hit, rtIntersectionDistance, );
// Buffers
rtBuffer<float3, 2> output_buffer;
// Function pointers for the OSL shader
rtDeclareVariable(rtCallableProgramId<void(void*, void*)>, osl_init_func, , );
rtDeclareVariable(rtCallableProgramId<void(void*, void*)>, osl_group_func, , );
RT_PROGRAM void
any_hit_shadow()
{
rtTerminateRay();
}
static __device__ void
globals_from_hit(ShaderGlobals& sg)
{
// Setup the ShaderGlobals
sg.I = ray.direction;
sg.N = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal));
sg.Ng = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, geometric_normal));
sg.P = ray.origin + t_hit * ray.direction;
sg.dPdu = dPdu;
sg.u = texcoord.x;
sg.v = texcoord.y;
sg.Ci = NULL;
sg.surfacearea = surface_area;
sg.backfacing = (dot(sg.N, sg.I) > 0.0f);
if (sg.backfacing) {
sg.N = -sg.N;
sg.Ng = -sg.Ng;
}
// NB: These variables are not used in the current iteration of the sample
sg.raytype = CAMERA;
sg.flipHandedness = 0;
}
static __device__ float3
process_closure(const OSL::ClosureColor* closure_tree)
{
OSL::Color3 result = OSL::Color3(0.0f);
if (!closure_tree) {
return make_float3(result.x, result.y, result.z);
}
// The depth of the closure tree must not exceed the stack size.
// A stack size of 8 is probably quite generous for relatively
// balanced trees.
const int STACK_SIZE = 8;
// Non-recursive traversal stack
int stack_idx = 0;
const OSL::ClosureColor* ptr_stack[STACK_SIZE];
OSL::Color3 weight_stack[STACK_SIZE];
// Shading accumulator
OSL::Color3 weight = OSL::Color3(1.0f);
const void* cur = closure_tree;
while (cur) {
switch (((OSL::ClosureColor*)cur)->id) {
case OSL::ClosureColor::ADD: {
ptr_stack[stack_idx] = ((OSL::ClosureAdd*)cur)->closureB;
weight_stack[stack_idx++] = weight;
cur = ((OSL::ClosureAdd*)cur)->closureA;
break;
}
case OSL::ClosureColor::MUL: {
weight *= ((OSL::ClosureMul*)cur)->weight;
cur = ((OSL::ClosureMul*)cur)->closure;
break;
}
case EMISSION_ID: {
cur = NULL;
break;
}
case DIFFUSE_ID:
case OREN_NAYAR_ID:
case PHONG_ID:
case WARD_ID:
case REFLECTION_ID:
case REFRACTION_ID:
case FRESNEL_REFLECTION_ID: {
result += ((OSL::ClosureComponent*)cur)->w * weight;
cur = NULL;
break;
}
case MICROFACET_ID: {
const char* mem = (const char*)((OSL::ClosureComponent*)cur)->data();
const char* dist_str = *(const char**)&mem[0];
# if 0
if (launch_index.x == launch_dim.x / 2 && launch_index.y == launch_dim.y / 2)
printf ("microfacet, dist: %s\n", HDSTR(dist_str).c_str());
# endif
if (HDSTR(dist_str) == OSL::DeviceStrings::default_)
return make_float3(0.0f, 1.0f, 1.0f);
return make_float3(1.0f, 0.0f, 1.0f);
}
default: cur = NULL; break;
}
if (cur == NULL && stack_idx > 0) {
cur = ptr_stack[--stack_idx];
weight = weight_stack[stack_idx];
}
}
return make_float3(result.x, result.y, result.z);
}
RT_PROGRAM void
closest_hit_osl()
{
// TODO: Fixed-sized allocations can easily be exceeded by arbitrary shader
// networks, so there should be (at least) some mechanism to issue a
// warning or error if the closure or param storage can possibly be
// exceeded.
alignas(8) char closure_pool[256];
alignas(8) char params[256];
ShaderGlobals sg;
globals_from_hit(sg);
// Pack the "closure pool" into one of the ShaderGlobals pointers
*(int*)&closure_pool[0] = 0;
sg.renderstate = &closure_pool[0];
// Create some run-time options structs. The OSL shader fills in the structs
// as it executes, based on the options specified in the shader source.
NoiseOptCUDA noiseopt;
TextureOptCUDA textureopt;
TraceOptCUDA traceopt;
// Pack the pointers to the options structs in a faux "context",
// which is a rough stand-in for the host ShadingContext.
ShadingContextCUDA shading_context = { &noiseopt, &textureopt, &traceopt };
sg.context = &shading_context;
// Run the OSL group and init functions
osl_init_func(&sg, params);
osl_group_func(&sg, params);
prd_radiance.result = process_closure((OSL::ClosureColor*)sg.Ci);
}
#else //#if (OPTIX_VERSION < 70000)
# include "../render_params.h"
extern "C" {
@@ -201,3 +392,5 @@ __closesthit__closest_hit_osl()
int pixel = launch_index.y * launch_dims.x + launch_index.x;
output_buffer[pixel] = make_float3(result.x, result.y, result.z);
}
#endif //#if (OPTIX_VERSION < 70000)
+174
View File
@@ -0,0 +1,174 @@
// Copyright Contributors to the Open Shading Language project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
#ifdef OSL_USE_OPTIX
# include <optix.h>
#endif
#if OPTIX_VERSION < 70000
# include "optix_stringtable.h"
using OIIO::ustring;
OSL_NAMESPACE_ENTER
OptiXStringTable::OptiXStringTable(optix::Context ctx)
: m_ptr(nullptr), m_size(1 << 16), m_offset(0), m_optix_ctx(ctx)
{
}
OptiXStringTable::~OptiXStringTable()
{
freetable();
}
void
OptiXStringTable::freetable()
{
if (m_ptr)
OSL::cudaFree(m_ptr);
m_ptr = nullptr;
}
void
OptiXStringTable::init(optix::Context ctx OSL_MAYBE_UNUSED)
{
# ifdef OSL_USE_OPTIX
OSL_ASSERT(!m_ptr && "StringTable should only be initialized once");
m_optix_ctx = ctx;
OSL_ASSERT((m_optix_ctx->getEnabledDeviceCount() == 1)
&& "Only one CUDA device is currently supported");
OSL::cudaMalloc(reinterpret_cast<void**>(&m_ptr), (m_size));
// Add the statically-declared strings to the table, and create OptiX
// variables for them in the OSL::DeviceStrings namespace.
//
// The names of the variables created here must match the extern variables
// declared in OSL/device_string.h for OptiX's variable scoping mechanisms
// to work.
# define STRDECL(str, var_name) \
addString(ustring(str), ustring(OSL_NAMESPACE_STRING \
"::DeviceStrings::" #var_name));
# include <OSL/strdecls.h>
# undef STRDECL
# endif
}
uint64_t
OptiXStringTable::addString(ustring str OSL_MAYBE_UNUSED,
ustring var_name OSL_MAYBE_UNUSED)
{
# ifdef OSL_USE_OPTIX
OSL_ASSERT(m_ptr && "StringTable has not been initialized");
// The strings are laid out in the table as a struct:
//
// struct TableRep {
// size_t len;
// size_t hash;
// char str[len+1];
// };
// Compute the size of the entry before adding it to the table
size_t size = sizeof(size_t) + sizeof(size_t) + str.size() + 1;
if (((m_offset + size) >= m_size)) {
reallocTable();
}
// It should be hard to trigger this assert, unless the table size is
// very small and the string is very large.
OSL_ASSERT(m_offset + size <= m_size && "String table allocation error");
int offset = getOffset(str.string());
if (offset < 0) {
// Place the hash and length of the string before the characters
size_t hash = str.hash();
cudaMemcpy(m_ptr + m_offset, (void*)&hash, sizeof(size_t),
cudaMemcpyHostToDevice);
m_offset += sizeof(size_t);
size_t len = str.length();
cudaMemcpy(m_ptr + m_offset, (void*)&len, sizeof(size_t),
cudaMemcpyHostToDevice);
m_offset += sizeof(size_t);
offset = m_offset;
m_offset_map[str] = offset;
m_name_map[str] = var_name;
// Copy the raw characters to the table
cudaMemcpy(m_ptr + m_offset, str.c_str(), str.size() + 1,
cudaMemcpyHostToDevice);
m_offset += str.size() + 1;
// Align the offset for the next entry to 8-byte boundaries
m_offset = (m_offset + 0x7u) & ~0x7u;
} else if (!var_name.empty()) {
// update what str points to
m_name_map[str] = var_name;
}
uint64_t addr = reinterpret_cast<uint64_t>(m_ptr + offset);
// Optionally create an OptiX variable for the string. It's not necessary to
// create a variable for strings that do not appear by name in compiled code
// (in either the OSL library functions or in the renderer).
if (!var_name.empty())
m_optix_ctx[var_name.string()]->setUserData(8, &addr);
return addr;
# else
return 0;
# endif
}
int
OptiXStringTable::getOffset(const std::string& str) const
{
auto it = m_offset_map.find(ustring(str));
return (it != m_offset_map.end()) ? it->second : -1;
}
void
OptiXStringTable::reallocTable()
{
# ifdef OSL_USE_OPTIX
OSL_ASSERT((m_optix_ctx->getEnabledDeviceCount() == 1)
&& "Only one CUDA device is currently supported");
m_size *= 2;
OSL::cudaFree(m_ptr);
OSL::cudaMalloc(reinterpret_cast<void**>(&m_ptr), (m_size));
// The offsets need to be recomputed
m_offset = 0;
m_offset_map.clear();
// Add the string collection to the newly-allocated memory
for (auto& entry : m_name_map) {
addString(entry.first, entry.second);
}
# endif
}
OSL_NAMESPACE_EXIT
#endif
+89
View File
@@ -0,0 +1,89 @@
// Copyright Contributors to the Open Shading Language project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
#pragma once
#include <map>
#include <unordered_map>
#include <utility>
#include "optix_compat.h"
#include <OSL/oslexec.h>
#include <OpenImageIO/ustring.h>
OSL_NAMESPACE_ENTER
typedef std::unordered_map<OIIO::ustring, int64_t, OIIO::ustringHash>
StringTableMap;
// The OptiXStringTable manages a block of CUDA device memory designated
// to hold all of the string constants that a shader might access during
// execution.
//
// Any string that needs to be visible on the device needs to be added using the
// addString function.
class OptiXStringTable {
public:
OptiXStringTable(optix::Context ctx = nullptr);
~OptiXStringTable();
// Allocate CUDA device memory for the raw string table and add the
// "standard" strings declared in strdecls.h.
void init(optix::Context ctx);
const StringTableMap& contents() const { return m_addr_table; }
// Add a string to the table (if it hasn't already been added), and return
// its address in device memory. Also, create an OptiX variable to hold the
// address of each string variable, through which the strings will be
// accessed during execution.
//
// Creating variables for the strings -- rather than using the string
// addresses directly -- is necessary for keeping the generated PTX stable
// from run to run, regardless of the order in which strings are added to
// the table. This helps make the PTX more cacheable.
//
// This function should not be called when a kernel that could potentially
// access the table is running, since it has the potential to invalidate
// pointers if reallocation is triggered.
uint64_t addString(OIIO::ustring str, OIIO::ustring var_name);
void freetable();
private:
// If a string has already been added to the table, return its offset in the
// char array; otherwise, return -1.
int getOffset(const std::string& str) const;
// Free the previous allocation, allocate a new block of GPU memory of twice
// the size, copy the string contents into the new allocation, and update the
// OptiX variables that hold the string addresses.
void reallocTable();
// A byte array containing the concatenation of all strings added to the
// table, allocated in CUDA device memory. The hash value and length of each
// string are stored in the 16 bytes preceding the raw characters.
char* m_ptr;
// The size of the table in bytes.
size_t m_size;
// The offset in the char array at which the next string will be added.
int m_offset;
// A handle on the OptiX Context to use when creating global variables.
optix::Context m_optix_ctx;
// The memory offsets associated with each canonical string.
std::map<OIIO::ustring, int> m_offset_map;
// The variable names associated with each canonical string.
std::map<OIIO::ustring, OIIO::ustring> m_name_map;
StringTableMap m_addr_table;
};
OSL_NAMESPACE_EXIT
+524 -110
View File
@@ -13,11 +13,14 @@
#include "render_params.h"
#include <cuda.h>
#include <optix_function_table_definition.h>
#include <optix_stack_size.h>
#include <optix_stubs.h>
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION >= 70000)
# include <cuda.h>
# include <optix_function_table_definition.h>
# include <optix_stack_size.h>
# include <optix_stubs.h>
# endif
#endif
// The pre-compiled renderer support library LLVM bitcode is embedded
// into the executable and made available through these variables.
@@ -27,41 +30,33 @@ extern unsigned char rend_llvm_compiled_ops_block[];
OSL_NAMESPACE_ENTER
#if (OPTIX_VERSION >= 70000)
#define CUDA_CHECK(call) \
{ \
cudaError_t res = call; \
if (res != cudaSuccess) { \
print(stderr, \
"[CUDA ERROR] Cuda call '{}' failed with error:" \
" {} ({}:{})\n", \
#call, cudaGetErrorString(res), __FILE__, __LINE__); \
} \
}
# define CUDA_CHECK(call) \
{ \
cudaError_t error = call; \
if (error != cudaSuccess) { \
std::stringstream ss; \
ss << "CUDA call (" << #call << " ) failed with error: '" \
<< cudaGetErrorString(error) << "' (" __FILE__ << ":" \
<< __LINE__ << ")\n"; \
print(stderr, "[CUDA ERROR] {}", ss.str()); \
} \
}
#define OPTIX_CHECK(call) \
{ \
OptixResult res = call; \
if (res != OPTIX_SUCCESS) { \
print(stderr, \
"[OPTIX ERROR] OptiX call '{}' failed with error:" \
" {} ({}:{})\n", \
#call, optixGetErrorName(res), __FILE__, __LINE__); \
exit(1); \
} \
}
#define OPTIX_CHECK_MSG(call, msg) \
{ \
OptixResult res = call; \
if (res != OPTIX_SUCCESS) { \
print(stderr, \
"[OPTIX ERROR] OptiX call '{}' failed with error:" \
" {} ({}:{})\nMessage: {}\n", \
#call, optixGetErrorName(res), __FILE__, __LINE__, msg); \
exit(1); \
} \
}
# define OPTIX_CHECK(call) \
{ \
OptixResult res = call; \
if (res != OPTIX_SUCCESS) { \
std::stringstream ss; \
ss << "Optix call '" << #call \
<< "' failed with error: " << optixGetErrorName(res) \
<< " (" __FILE__ ":" << __LINE__ << ")\n"; \
print(stderr, "[OPTIX ERROR] {}", ss.str()); \
exit(1); \
} \
}
#endif
#define CUDA_SYNC_CHECK() \
{ \
@@ -74,17 +69,18 @@ OSL_NAMESPACE_ENTER
} \
}
#if defined(OSL_USE_OPTIX) && OPTIX_VERSION >= 70000
static void
context_log_cb(unsigned int level, const char* tag, const char* message,
void* /*cbdata */)
{
// std::cerr << "[ ** LOGCALLBACK** " << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n";
}
#endif
OptixRaytracer::OptixRaytracer()
{
#if defined(OSL_USE_OPTIX) && OPTIX_VERSION >= 70000
// Initialize CUDA
cudaFree(0);
@@ -99,22 +95,36 @@ OptixRaytracer::OptixRaytracer()
CUDA_CHECK(cudaSetDevice(0));
CUDA_CHECK(cudaStreamCreate(&m_cuda_stream));
# define STRDECL(str, var_name) \
register_string(str, \
OSL_NAMESPACE_STRING "::DeviceStrings::" #var_name);
# include <OSL/strdecls.h>
# undef STRDECL
#endif
}
OptixRaytracer::~OptixRaytracer()
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
m_str_table.freetable();
if (m_optix_ctx)
m_optix_ctx->destroy();
# else
if (m_optix_ctx)
OPTIX_CHECK(optixDeviceContextDestroy(m_optix_ctx));
# endif
#endif
}
uint64_t
OptixRaytracer::register_global(const std::string& str, uint64_t value)
{
auto it = m_globals_map.find(ustring(str));
if (it != m_globals_map.end()) {
return it->second;
}
@@ -122,8 +132,6 @@ OptixRaytracer::register_global(const std::string& str, uint64_t value)
return value;
}
bool
OptixRaytracer::fetch_global(const std::string& str, uint64_t* value)
{
@@ -136,11 +144,10 @@ OptixRaytracer::fetch_global(const std::string& str, uint64_t* value)
return false;
}
std::string
OptixRaytracer::load_ptx_file(string_view filename)
{
#ifdef OSL_USE_OPTIX
std::vector<std::string> paths
= { OIIO::Filesystem::parent_path(OIIO::Sysutil::this_program_path()),
PTX_PATH };
@@ -151,6 +158,7 @@ OptixRaytracer::load_ptx_file(string_view filename)
if (OIIO::Filesystem::read_text_file(filepath, ptx_string))
return ptx_string;
}
#endif
errhandler().severefmt("Unable to load {}", filename);
return {};
}
@@ -161,6 +169,85 @@ bool
OptixRaytracer::init_optix_context(int xres OSL_MAYBE_UNUSED,
int yres OSL_MAYBE_UNUSED)
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
// NB: renderers using OptiX7+ are expected to link it rend_lib.cu manually
// to avoid duplicate 'rend_lib' symbols in each shader group.
shadingsys->attribute("lib_bitcode",
{ OSL::TypeDesc::UINT8, rend_llvm_compiled_ops_size },
rend_llvm_compiled_ops_block);
// Set up the OptiX context
m_optix_ctx = optix::Context::create();
// Set up the string table. This allocates a block of CUDA device memory to
// hold all of the static strings used by the OSL shaders. The strings can
// be accessed via OptiX variables that hold pointers to the table entries.
m_str_table.init(m_optix_ctx);
if (m_optix_ctx->getEnabledDeviceCount() != 1)
errhandler().warningfmt("Only one CUDA device is currently supported");
m_optix_ctx->setRayTypeCount(2);
m_optix_ctx->setEntryPointCount(1);
m_optix_ctx->setStackSize(2048);
m_optix_ctx->setPrintEnabled(true);
// Load the renderer CUDA source and generate PTX for it
std::string progName = "optix_raytracer.ptx";
std::string renderer_ptx = load_ptx_file(progName);
if (renderer_ptx.empty()) {
errhandler().severefmt("Could not find PTX for the raygen program");
return false;
}
// Create the OptiX programs and set them on the optix::Context
m_program = m_optix_ctx->createProgramFromPTXString(renderer_ptx, "raygen");
m_optix_ctx->setRayGenerationProgram(0, m_program);
if (scene.num_prims()) {
m_optix_ctx["radiance_ray_type"]->setUint(0u);
m_optix_ctx["shadow_ray_type"]->setUint(1u);
m_optix_ctx["bg_color"]->setFloat(0.0f, 0.0f, 0.0f);
m_optix_ctx["bad_color"]->setFloat(1.0f, 0.0f, 1.0f);
// Create the OptiX programs and set them on the optix::Context
if (renderer_ptx.size()) {
m_optix_ctx->setMissProgram(
0,
m_optix_ctx->createProgramFromPTXString(renderer_ptx, "miss"));
m_optix_ctx->setExceptionProgram(
0, m_optix_ctx->createProgramFromPTXString(renderer_ptx,
"exception"));
}
// Load the PTX for the wrapper program. It will be used to
// create OptiX Materials from the OSL ShaderGroups
m_materials_ptx = load_ptx_file("wrapper.ptx");
if (m_materials_ptx.empty())
return false;
// Load the PTX for the primitives
std::string sphere_ptx = load_ptx_file("sphere.ptx");
std::string quad_ptx = load_ptx_file("quad.ptx");
if (sphere_ptx.empty() || quad_ptx.empty())
return false;
// Create the sphere and quad intersection programs.
sphere_bounds = m_optix_ctx->createProgramFromPTXString(sphere_ptx,
"bounds");
quad_bounds = m_optix_ctx->createProgramFromPTXString(quad_ptx,
"bounds");
sphere_intersect = m_optix_ctx->createProgramFromPTXString(sphere_ptx,
"intersect");
quad_intersect = m_optix_ctx->createProgramFromPTXString(quad_ptx,
"intersect");
}
# endif //#if (OPTIX_VERSION < 70000)
#endif
return true;
}
@@ -169,11 +256,89 @@ OptixRaytracer::init_optix_context(int xres OSL_MAYBE_UNUSED,
bool
OptixRaytracer::synch_attributes()
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
// FIXME -- this is for testing only
// Make some device strings to test userdata parameters
uint64_t addr1 = register_string("ud_str_1", "");
uint64_t addr2 = register_string("userdata string", "");
m_optix_ctx["test_str_1"]->setUserData(sizeof(char*), &addr1);
m_optix_ctx["test_str_2"]->setUserData(sizeof(char*), &addr2);
{
const char* name = OSL_NAMESPACE_STRING "::pvt::s_color_system";
char* colorSys = nullptr;
long long cpuDataSizes[2] = { 0, 0 };
if (!shadingsys->getattribute("colorsystem", TypeDesc::PTR,
(void*)&colorSys)
|| !shadingsys->getattribute("colorsystem:sizes",
TypeDesc(TypeDesc::LONGLONG, 2),
(void*)&cpuDataSizes)
|| !colorSys || !cpuDataSizes[0]) {
errhandler().errorfmt("No colorsystem available.");
return false;
}
auto cpuDataSize = cpuDataSizes[0];
auto numStrings = cpuDataSizes[1];
// Get the size data-size, minus the ustring size
const size_t podDataSize = cpuDataSize
- sizeof(StringParam) * numStrings;
optix::Buffer buffer = m_optix_ctx->createBuffer(RT_BUFFER_INPUT,
RT_FORMAT_USER);
if (!buffer) {
errhandler().errorfmt("Could not create buffer for '{}'.", name);
return false;
}
// set the element size to char
buffer->setElementSize(sizeof(char));
// and number of elements to the actual size needed.
buffer->setSize(podDataSize + sizeof(DeviceString) * numStrings);
// copy the base data
char* gpuData = (char*)buffer->map();
if (!gpuData) {
errhandler().errorfmt("Could not map buffer for '{}' (size: {}).",
name,
podDataSize
+ sizeof(DeviceString) * numStrings);
return false;
}
::memcpy(gpuData, colorSys, podDataSize);
// then copy the device string to the end, first strings starting at dataPtr - (numStrings)
// FIXME -- Should probably handle alignment better.
const ustring* cpuString
= (const ustring*)(colorSys
+ (cpuDataSize
- sizeof(StringParam) * numStrings));
char* gpuStrings = gpuData + podDataSize;
for (const ustring* end = cpuString + numStrings; cpuString < end;
++cpuString) {
// convert the ustring to a device string
uint64_t devStr = register_string(cpuString->string(), "");
::memcpy(gpuStrings, &devStr, sizeof(devStr));
gpuStrings += sizeof(DeviceString);
}
buffer->unmap();
m_optix_ctx[name]->setBuffer(buffer);
}
# else // #if (OPTIX_VERSION < 70000)
// FIXME -- this is for testing only
// Make some device strings to test userdata parameters
ustring userdata_str1("ud_str_1");
ustring userdata_str2("userdata string");
register_string(userdata_str1.string(), "");
register_string(userdata_str2.string(), "");
// Store the user-data
test_str_1 = userdata_str1.hash();
test_str_2 = userdata_str2.hash();
@@ -218,17 +383,18 @@ OptixRaytracer::synch_attributes()
for (const ustring* end = cpuString + numStrings; cpuString < end;
++cpuString) {
// convert the ustring to a device string
uint64_t devStr = cpuString->hash();
uint64_t devStr = register_string(cpuString->string(), "");
CUDA_CHECK(cudaMemcpy(reinterpret_cast<void*>(gpuStrings), &devStr,
sizeof(devStr), cudaMemcpyHostToDevice));
gpuStrings += sizeof(DeviceString);
}
}
# endif // #if (OPTIX_VERSION < 70000)
#endif
return true;
}
#if (OPTIX_VERSION >= 70000)
bool
OptixRaytracer::load_optix_module(
const char* filename,
@@ -246,18 +412,16 @@ OptixRaytracer::load_optix_module(
}
size_t sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(optixModuleCreateFromPTX(m_optix_ctx,
module_compile_options,
pipeline_compile_options,
program_ptx.c_str(),
program_ptx.size(), msg_log,
&sizeof_msg_log, program_module),
fmtformat("Creating Module from PTX-file {}", msg_log));
OPTIX_CHECK(optixModuleCreateFromPTX(m_optix_ctx, module_compile_options,
pipeline_compile_options,
program_ptx.c_str(),
program_ptx.size(), msg_log,
&sizeof_msg_log, program_module));
//if (sizeof_msg_log > 1)
// printf ("Creating Module from PTX-file %s:\n%s\n", filename, msg_log);
return true;
}
bool
OptixRaytracer::create_optix_pg(const OptixProgramGroupDesc* pg_desc,
const int num_pg,
@@ -266,19 +430,103 @@ OptixRaytracer::create_optix_pg(const OptixProgramGroupDesc* pg_desc,
{
char msg_log[8192];
size_t sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(optixProgramGroupCreate(m_optix_ctx, pg_desc, num_pg,
program_options, msg_log,
&sizeof_msg_log, pg),
fmtformat("Creating program group: {}", msg_log));
OPTIX_CHECK(optixProgramGroupCreate(m_optix_ctx, pg_desc, num_pg,
program_options, msg_log,
&sizeof_msg_log, pg));
//if (sizeof_msg_log > 1)
// printf ("Creating program group:\n%s\n", msg_log);
return true;
}
#endif
bool
OptixRaytracer::make_optix_materials()
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
optix::Program closest_hit, any_hit;
if (scene.num_prims()) {
closest_hit = m_optix_ctx->createProgramFromPTXString(m_materials_ptx,
"closest_hit_osl");
any_hit = m_optix_ctx->createProgramFromPTXString(m_materials_ptx,
"any_hit_shadow");
}
// Stand-in: names of shader outputs to preserve
// FIXME
std::vector<const char*> outputs { "Cout" };
// Optimize each ShaderGroup in the scene, and use the resulting
// PTX to create OptiX Programs which can be called by the closest
// hit program in the wrapper to execute the compiled OSL shader.
int mtl_id = 0;
for (const auto& groupref : shaders()) {
shadingsys->attribute(groupref.get(), "renderer_outputs",
TypeDesc(TypeDesc::STRING, outputs.size()),
outputs.data());
shadingsys->optimize_group(groupref.get(), nullptr);
if (!scene.num_prims()) {
if (!shadingsys->find_symbol(*groupref.get(), ustring(outputs[0]))) {
errhandler().warningfmt(
"Requested output '{}', which wasn't found", outputs[0]);
}
}
std::string group_name, init_name, entry_name;
shadingsys->getattribute(groupref.get(), "groupname", group_name);
shadingsys->getattribute(groupref.get(), "group_init_name", init_name);
shadingsys->getattribute(groupref.get(), "group_entry_name",
entry_name);
// Retrieve the compiled ShaderGroup PTX
std::string osl_ptx;
shadingsys->getattribute(groupref.get(), "ptx_compiled_version",
OSL::TypeDesc::PTR, &osl_ptx);
if (osl_ptx.empty()) {
errhandler().errorfmt("Failed to generate PTX for ShaderGroup {}",
group_name);
return false;
}
if (options.get_int("saveptx")) {
std::string filename = fmtformat("{}_{}.ptx", group_name, mtl_id++);
OIIO::Filesystem::write_text_file(filename, osl_ptx);
}
// Create Programs from the init and group_entry functions,
// and set the OSL functions as Callable Programs so that they
// can be executed by the closest hit program in the wrapper
optix::Program osl_init
= m_optix_ctx->createProgramFromPTXString(osl_ptx, init_name);
optix::Program osl_group
= m_optix_ctx->createProgramFromPTXString(osl_ptx, entry_name);
if (scene.num_prims()) {
// Create a new Material using the wrapper PTX
optix::Material mtl = m_optix_ctx->createMaterial();
mtl->setClosestHitProgram(0, closest_hit);
mtl->setAnyHitProgram(1, any_hit);
// Set the OSL functions as Callable Programs so that they can be
// executed by the closest hit program in the wrapper
mtl["osl_init_func"]->setProgramId(osl_init);
mtl["osl_group_func"]->setProgramId(osl_group);
scene.optix_mtls.push_back(mtl);
} else {
// Grid shading
m_program["osl_init_func"]->setProgramId(osl_init);
m_program["osl_group_func"]->setProgramId(osl_group);
}
}
if (!synch_attributes())
return false;
# else //#if (OPTIX_VERSION < 70000)
// Stand-in: names of shader outputs to preserve
std::vector<const char*> outputs { "Cout" };
@@ -293,12 +541,12 @@ OptixRaytracer::make_optix_materials()
module_compile_options.maxRegisterCount
= OPTIX_COMPILE_DEFAULT_MAX_REGISTER_COUNT;
module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT;
#if OPTIX_VERSION >= 70400
module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT;
# if OPTIX_VERSION >= 70400
module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_MINIMAL;
#else
# else
module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO;
#endif
# endif
OptixPipelineCompileOptions pipeline_compile_options = {};
@@ -358,13 +606,14 @@ OptixRaytracer::make_optix_materials()
OptixProgramGroup setglobals_raygen_group;
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(
optixProgramGroupCreate(m_optix_ctx, &setglobals_raygen_desc,
1, // number of program groups
&program_options, // program options
msg_log, &sizeof_msg_log,
&setglobals_raygen_group),
fmtformat("Creating set-globals 'ray-gen' program group: {}", msg_log));
OPTIX_CHECK(optixProgramGroupCreate(m_optix_ctx, &setglobals_raygen_desc,
1, // number of program groups
&program_options, // program options
msg_log, &sizeof_msg_log,
&setglobals_raygen_group));
//if (sizeof_msg_log > 1)
// printf ("Creating set-globals 'ray-gen' program group:\n%s\n", msg_log);
// Miss group
OptixProgramGroupDesc miss_desc = {};
@@ -492,13 +741,13 @@ OptixRaytracer::make_optix_materials()
// and set the OSL functions as Callable Programs so that they
// can be executed by the closest hit program in the wrapper
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(
OPTIX_CHECK(
optixModuleCreateFromPTX(m_optix_ctx, &module_compile_options,
&pipeline_compile_options, osl_ptx.c_str(),
osl_ptx.size(), msg_log, &sizeof_msg_log,
&optix_module),
fmtformat("Creating module for PTX group {}: {}", group_name,
msg_log));
&optix_module));
//if (sizeof_msg_log > 1)
// printf ("Creating module for PTX group '%s':\n%s\n", group_name.c_str(), msg_log);
modules.push_back(optix_module);
// Create 2x program groups (for direct callables)
@@ -516,20 +765,21 @@ OptixRaytracer::make_optix_materials()
shader_groups.resize(shader_groups.size() + 2);
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(
OPTIX_CHECK(
optixProgramGroupCreate(m_optix_ctx, &pgDesc[0], 2,
&program_options, msg_log, &sizeof_msg_log,
&shader_groups[shader_groups.size() - 2]),
fmtformat("Creating 'shader' group for group {}: {}", group_name,
msg_log));
&shader_groups[shader_groups.size() - 2]));
//if (sizeof_msg_log > 1)
// printf ("Creating 'shader' group for group '%s':\n%s\n", group_name.c_str(), msg_log);
}
OptixPipelineLinkOptions pipeline_link_options;
pipeline_link_options.maxTraceDepth = 1;
pipeline_link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL;
#if (OPTIX_VERSION < 70100)
# if (OPTIX_VERSION < 70100)
pipeline_link_options.overrideUsesMotionBlur = false;
#endif
# endif
// Set up OptiX pipeline
std::vector<OptixProgramGroup> final_groups = { rend_lib_group,
@@ -552,12 +802,12 @@ OptixRaytracer::make_optix_materials()
final_groups.push_back(setglobals_miss_group);
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(optixPipelineCreate(m_optix_ctx, &pipeline_compile_options,
&pipeline_link_options,
final_groups.data(),
int(final_groups.size()), msg_log,
&sizeof_msg_log, &m_optix_pipeline),
fmtformat("Creating optix pipeline: {}", msg_log));
OPTIX_CHECK(optixPipelineCreate(m_optix_ctx, &pipeline_compile_options,
&pipeline_link_options, final_groups.data(),
int(final_groups.size()), msg_log,
&sizeof_msg_log, &m_optix_pipeline));
//if (sizeof_msg_log > 1)
// printf ("Creating optix pipeline:\n%s\n", msg_log);
// Set the pipeline stack size
OptixStackSizes stack_sizes = {};
@@ -689,14 +939,75 @@ OptixRaytracer::make_optix_materials()
}
modules.clear();
# endif //#if (OPTIX_VERSION < 70000)
#endif
return true;
}
bool
OptixRaytracer::finalize_scene()
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
make_optix_materials();
// Create a GeometryGroup to contain the scene geometry
optix::GeometryGroup geom_group = m_optix_ctx->createGeometryGroup();
m_optix_ctx["top_object"]->set(geom_group);
m_optix_ctx["top_shadower"]->set(geom_group);
// NB: Since the scenes in the test suite consist of only a few primitives,
// using 'NoAccel' instead of 'Trbvh' might yield a slight performance
// improvement. For more complex scenes (e.g., scenes with meshes),
// using 'Trbvh' is recommended to achieve maximum performance.
geom_group->setAcceleration(m_optix_ctx->createAcceleration("Trbvh"));
// Translate the primitives parsed from the scene description into OptiX scene
// objects
for (const auto& sphere : scene.spheres) {
optix::Geometry sphere_geom = m_optix_ctx->createGeometry();
sphere.setOptixVariables(sphere_geom, sphere_bounds, sphere_intersect);
optix::GeometryInstance sphere_gi = m_optix_ctx->createGeometryInstance(
sphere_geom, &scene.optix_mtls[sphere.shaderid()],
&scene.optix_mtls[sphere.shaderid()] + 1);
geom_group->addChild(sphere_gi);
}
for (const auto& quad : scene.quads) {
optix::Geometry quad_geom = m_optix_ctx->createGeometry();
quad.setOptixVariables(quad_geom, quad_bounds, quad_intersect);
optix::GeometryInstance quad_gi = m_optix_ctx->createGeometryInstance(
quad_geom, &scene.optix_mtls[quad.shaderid()],
&scene.optix_mtls[quad.shaderid()] + 1);
geom_group->addChild(quad_gi);
}
// Set the camera variables on the OptiX Context, to be used by the ray gen program
m_optix_ctx["eye"]->setFloat(vec3_to_float3(camera.eye));
m_optix_ctx["dir"]->setFloat(vec3_to_float3(camera.dir));
m_optix_ctx["cx"]->setFloat(vec3_to_float3(camera.cx));
m_optix_ctx["cy"]->setFloat(vec3_to_float3(camera.cy));
m_optix_ctx["invw"]->setFloat(camera.invw);
m_optix_ctx["invh"]->setFloat(camera.invh);
// Create the output buffer
optix::Buffer buffer = m_optix_ctx->createBuffer(RT_BUFFER_OUTPUT,
RT_FORMAT_FLOAT3,
camera.xres, camera.yres);
m_optix_ctx["output_buffer"]->set(buffer);
m_optix_ctx->validate();
# else //#if (OPTIX_VERSION < 70000)
// Build acceleration structures
OptixAccelBuildOptions accelOptions;
OptixBuildInput buildInputs[2];
@@ -749,13 +1060,13 @@ OptixRaytracer::finalize_scene()
unsigned int quadSbtRecord;
quadSbtRecord = OPTIX_GEOMETRY_FLAG_NONE;
if (scene.quads.size() > 0) {
#if (OPTIX_VERSION < 70100)
# if (OPTIX_VERSION < 70100)
OptixBuildInputCustomPrimitiveArray& quadsInput
= buildInputs[numBuildInputs].aabbArray;
#else
# else
OptixBuildInputCustomPrimitiveArray& quadsInput
= buildInputs[numBuildInputs].customPrimitiveArray;
#endif
# endif
buildInputs[numBuildInputs].type
= OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES;
quadsInput.flags = &quadSbtRecord;
@@ -809,13 +1120,13 @@ OptixRaytracer::finalize_scene()
unsigned int sphereSbtRecord;
sphereSbtRecord = OPTIX_GEOMETRY_FLAG_NONE;
if (scene.spheres.size() > 0) {
#if (OPTIX_VERSION < 70100)
# if (OPTIX_VERSION < 70100)
OptixBuildInputCustomPrimitiveArray& spheresInput
= buildInputs[numBuildInputs].aabbArray;
#else
# else
OptixBuildInputCustomPrimitiveArray& spheresInput
= buildInputs[numBuildInputs].customPrimitiveArray;
#endif
# endif
buildInputs[numBuildInputs].type
= OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES;
spheresInput.flags = &sphereSbtRecord;
@@ -863,6 +1174,9 @@ OptixRaytracer::finalize_scene()
// h_aabb.maxX, h_aabb.maxY, h_aabb.maxZ );
make_optix_materials();
# endif //#if (OPTIX_VERSION < 70000)
#endif //#ifdef OSL_USE_OPTIX
return true;
}
@@ -874,7 +1188,17 @@ OptixRaytracer::finalize_scene()
bool
OptixRaytracer::good(TextureHandle* handle OSL_MAYBE_UNUSED)
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
return intptr_t(handle) != RT_TEXTURE_ID_NULL;
# else
return handle != nullptr;
# endif
#else
return false;
#endif
}
@@ -886,6 +1210,58 @@ OptixRaytracer::get_texture_handle(ustring filename OSL_MAYBE_UNUSED,
ShadingContext* shading_context
OSL_MAYBE_UNUSED)
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
auto itr = m_samplers.find(filename);
if (itr == m_samplers.end()) {
optix::TextureSampler sampler = context()->createTextureSampler();
sampler->setWrapMode(0, RT_WRAP_REPEAT);
sampler->setWrapMode(1, RT_WRAP_REPEAT);
sampler->setWrapMode(2, RT_WRAP_REPEAT);
sampler->setFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR,
RT_FILTER_NONE);
sampler->setIndexingMode(false
? RT_TEXTURE_INDEX_ARRAY_INDEX
: RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
sampler->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
sampler->setMaxAnisotropy(1.0f);
OIIO::ImageBuf image;
if (!image.init_spec(filename, 0, 0)) {
errhandler().errorfmt("Could not load: {}", filename);
return (TextureHandle*)(intptr_t(RT_TEXTURE_ID_NULL));
}
int nchan = image.spec().nchannels;
OIIO::ROI roi = OIIO::get_roi_full(image.spec());
int width = roi.width(), height = roi.height();
std::vector<float> pixels(width * height * nchan);
image.get_pixels(roi, OIIO::TypeDesc::FLOAT, pixels.data());
optix::Buffer buffer = context()->createBuffer(RT_BUFFER_INPUT,
RT_FORMAT_FLOAT4, width,
height);
float* device_ptr = static_cast<float*>(buffer->map());
unsigned int pixel_idx = 0;
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
memcpy(device_ptr, &pixels[pixel_idx], sizeof(float) * nchan);
device_ptr += 4;
pixel_idx += nchan;
}
}
buffer->unmap();
sampler->setBuffer(buffer);
itr = m_samplers.emplace(std::move(filename), std::move(sampler)).first;
}
return (RendererServices::TextureHandle*)intptr_t(itr->second->getId());
# else //#if (OPTIX_VERSION < 70000)
auto itr = m_samplers.find(filename);
if (itr == m_samplers.end()) {
// Open image
@@ -941,6 +1317,12 @@ OptixRaytracer::get_texture_handle(ustring filename OSL_MAYBE_UNUSED,
itr = m_samplers.emplace(std::move(filename), std::move(cuda_tex)).first;
}
return reinterpret_cast<RendererServices::TextureHandle*>(itr->second);
# endif //#if (OPTIX_VERSION < 70000)
#else
return nullptr;
#endif
}
@@ -948,11 +1330,13 @@ OptixRaytracer::get_texture_handle(ustring filename OSL_MAYBE_UNUSED,
void
OptixRaytracer::prepare_render()
{
#ifdef OSL_USE_OPTIX
// Set up the OptiX Context
init_optix_context(camera.xres, camera.yres);
// Set up the OptiX scene graph
finalize_scene();
#endif
}
@@ -960,10 +1344,16 @@ OptixRaytracer::prepare_render()
void
OptixRaytracer::warmup()
{
#ifdef OSL_USE_OPTIX
// Perform a tiny launch to warm up the OptiX context
# if (OPTIX_VERSION < 70000)
m_optix_ctx->launch(0, 1, 1);
# else
OPTIX_CHECK(optixLaunch(m_optix_pipeline, m_cuda_stream, d_launch_params,
sizeof(RenderParams), &m_optix_sbt, 0, 0, 1));
CUDA_SYNC_CHECK();
# endif
#endif
}
@@ -971,11 +1361,16 @@ OptixRaytracer::warmup()
void
OptixRaytracer::render(int xres OSL_MAYBE_UNUSED, int yres OSL_MAYBE_UNUSED)
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
m_optix_ctx->launch(0, xres, yres);
# else
CUDA_CHECK(cudaMalloc(reinterpret_cast<void**>(&d_output_buffer),
xres * yres * 4 * sizeof(float)));
CUDA_CHECK(cudaMalloc(reinterpret_cast<void**>(&d_launch_params),
sizeof(RenderParams)));
m_xres = xres;
m_yres = yres;
@@ -1026,10 +1421,11 @@ OptixRaytracer::render(int xres OSL_MAYBE_UNUSED, int yres OSL_MAYBE_UNUSED)
OSL_PRINTF_BUFFER_SIZE, cudaMemcpyDeviceToHost));
processPrintfBuffer(printf_buffer.data(), OSL_PRINTF_BUFFER_SIZE);
# endif
#endif
}
#if defined(OSL_USE_OPTIX) && OPTIX_VERSION >= 70000
void
OptixRaytracer::processPrintfBuffer(void* buffer_data, size_t buffer_size)
{
@@ -1054,9 +1450,10 @@ OptixRaytracer::processPrintfBuffer(void* buffer_data, size_t buffer_size)
// have we reached the end?
if (fmt_str_hash == 0)
break;
const char* format = ustring::from_hash(fmt_str_hash).c_str();
OSL_ASSERT(format != nullptr
&& "The string should have been a valid ustring");
const char* format = m_hash_map[fmt_str_hash];
OSL_ASSERT(
format != nullptr
&& "The format string should have been registered with the renderer");
const size_t len = strlen(format);
for (size_t j = 0; j < len; j++) {
@@ -1072,7 +1469,7 @@ OptixRaytracer::processPrintfBuffer(void* buffer_data, size_t buffer_size)
switch (format[j]) {
case '%':
// seems like a silly to print a '%', but it keeps the logic parallel with the other cases
dst += snprintf(&buffer[dst], BufferSize - dst,
dst += snprintf(&buffer[dst], BufferSize - dst, "%s",
fmt_string.c_str());
format_end_found = true;
break;
@@ -1106,10 +1503,10 @@ OptixRaytracer::processPrintfBuffer(void* buffer_data, size_t buffer_size)
& ~(sizeof(double) - 1);
uint64_t str_hash = *reinterpret_cast<const uint64_t*>(
&ptr[src]);
const char* str = ustring::from_hash(str_hash).c_str();
const char* str = m_hash_map[str_hash];
OSL_ASSERT(
str != nullptr
&& "The string should have been a valid ustring");
&& "The string should have been regisgtered with the renderer");
dst += snprintf(&buffer[dst], BufferSize - dst,
fmt_string.c_str(), str);
src += sizeof(uint64_t);
@@ -1131,19 +1528,27 @@ OptixRaytracer::processPrintfBuffer(void* buffer_data, size_t buffer_size)
printf("%s", buffer);
}
}
#endif
void
OptixRaytracer::finalize_pixel_buffer()
{
#ifdef OSL_USE_OPTIX
std::string buffer_name = "output_buffer";
# if (OPTIX_VERSION < 70000)
const void* buffer_ptr = m_optix_ctx[buffer_name]->getBuffer()->map();
if (!buffer_ptr)
errhandler().severefmt("Unable to map buffer {}", buffer_name);
pixelbuf.set_pixels(OIIO::ROI::All(), OIIO::TypeFloat, buffer_ptr);
# else
std::vector<float> tmp_buff(m_xres * m_yres * 3);
CUDA_CHECK(cudaMemcpy(tmp_buff.data(),
reinterpret_cast<void*>(d_output_buffer),
m_xres * m_yres * 3 * sizeof(float),
cudaMemcpyDeviceToHost));
pixelbuf.set_pixels(OIIO::ROI::All(), OIIO::TypeFloat, tmp_buff.data());
# endif
#endif
}
@@ -1152,8 +1557,17 @@ void
OptixRaytracer::clear()
{
shaders().clear();
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
if (m_optix_ctx) {
m_optix_ctx->destroy();
m_optix_ctx = nullptr;
}
# else
OPTIX_CHECK(optixDeviceContextDestroy(m_optix_ctx));
m_optix_ctx = 0;
# endif
#endif
}
OSL_NAMESPACE_EXIT
+51 -10
View File
@@ -11,8 +11,11 @@
#include <OSL/device_string.h>
#include "optix_compat.h"
#include "render_params.h"
#include "simpleraytracer.h"
#if OPTIX_VERSION < 70000
# include "optix_stringtable.h"
#endif
#include "render_params.h"
OSL_NAMESPACE_ENTER
@@ -25,6 +28,21 @@ public:
OptixRaytracer();
virtual ~OptixRaytracer();
uint64_t register_string(const std::string& str,
const std::string& var_name)
{
ustring ustr = ustring(str);
#if OPTIX_VERSION < 70000
uint64_t addr = m_str_table.addString(ustr, ustring(var_name));
if (!var_name.empty())
register_global(var_name, addr);
return addr;
#else
m_hash_map[ustr.hash()] = ustr.c_str();
return 0;
#endif
}
uint64_t register_global(const std::string& str, uint64_t value);
bool fetch_global(const std::string& str, uint64_t* value);
@@ -58,30 +76,50 @@ public:
ShadingContext* shading_context);
// Easy way to do Optix calls
optix::Context& optix_ctx() { return m_optix_ctx; }
optix::Context& context() { return m_optix_ctx; }
optix::Context& operator->() { return context(); }
optix::Context& optix_ctx()
{
return m_optix_ctx;
}
optix::Context& context()
{
return m_optix_ctx;
}
optix::Context& operator->()
{
return context();
}
#if (OPTIX_VERSION >= 70000)
void processPrintfBuffer(void* buffer_data, size_t buffer_size);
#endif
private:
optix::Context m_optix_ctx = nullptr;
#if (OPTIX_VERSION < 70000)
OptiXStringTable m_str_table;
optix::Program m_program = nullptr;
optix::Program sphere_intersect = nullptr;
optix::Program sphere_bounds = nullptr;
optix::Program quad_intersect = nullptr;
optix::Program quad_bounds = nullptr;
#else
CUstream m_cuda_stream;
OptixTraversableHandle m_travHandle;
OptixShaderBindingTable m_optix_sbt = {};
OptixShaderBindingTable m_optix_sbt = {};
OptixShaderBindingTable m_setglobals_optix_sbt = {};
OptixPipeline m_optix_pipeline = {};
OptixPipeline m_optix_pipeline = {};
CUdeviceptr d_output_buffer;
CUdeviceptr d_launch_params = 0;
CUdeviceptr d_quads_list = 0;
CUdeviceptr d_spheres_list = 0;
CUdeviceptr d_quads_list = 0;
CUdeviceptr d_spheres_list = 0;
int m_xres, m_yres;
CUdeviceptr d_osl_printf_buffer;
CUdeviceptr d_color_system;
uint64_t test_str_1;
uint64_t test_str_2;
const unsigned long OSL_PRINTF_BUFFER_SIZE = 8 * 1024 * 1024;
std::unordered_map<uint64_t, const char*> m_hash_map;
bool load_optix_module(
const char* filename,
@@ -92,9 +130,12 @@ private:
OptixProgramGroupOptions* program_options,
OptixProgramGroup* pg);
#endif
std::string m_materials_ptx;
std::unordered_map<OIIO::ustring, optix::TextureSampler> m_samplers;
std::unordered_map<OIIO::ustring, uint64_t> m_globals_map;
std::unordered_map<OIIO::ustring, optix::TextureSampler, OIIO::ustringHash>
m_samplers;
std::unordered_map<OIIO::ustring, uint64_t, OIIO::ustringHash> m_globals_map;
};
+71 -3
View File
@@ -17,6 +17,15 @@
#ifdef OSL_USE_OPTIX
# include <optix.h>
# if (OPTIX_VERSION < 70000)
// Converts from Imath::Vec3 to optix::float3
inline optix::float3
vec3_to_float3(const OSL::Vec3& vec)
{
return optix::make_float3(vec.x, vec.y, vec.z);
}
# endif
# include <vector_functions.h> // from CUDA
#endif
@@ -43,8 +52,24 @@ ortho(const Vec3& n, Vec3& x, Vec3& y)
// Note: not used in OptiX mode
struct Ray {
Ray(const Vec3& o, const Vec3& d, float radius, float spread)
: origin(o), direction(d), radius(radius), spread(spread)
enum RayType {
CAMERA = 1,
SHADOW = 2,
REFLECTION = 4,
REFRACTION = 8,
DIFFUSE = 16,
GLOSSY = 32,
SUBSURFACE = 64,
DISPLACEMENT = 128
};
Ray(const Vec3& o, const Vec3& d, float radius, float spread,
RayType raytype)
: origin(o)
, direction(d)
, radius(radius)
, spread(spread)
, raytype(static_cast<int>(raytype))
{
}
@@ -72,6 +97,7 @@ struct Ray {
Vec3 origin, direction;
float radius, spread;
int raytype;
};
@@ -116,7 +142,7 @@ struct Camera {
const float cos_a = dir.dot(v);
const float spread
= sqrtf(invw * invh * cx.length() * cy.length() * cos_a) * cos_a;
return Ray(eye, v, 0, spread);
return Ray(eye, v, 0, spread, Ray::CAMERA);
}
// Specified by user:
@@ -151,7 +177,12 @@ struct Primitive {
float& maxy, float& maxz) const;
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
virtual void setOptixVariables(optix::Geometry geom, optix::Program bounds,
optix::Program intersect) const = 0;
# else
virtual void setOptixVariables(void* data) const = 0;
# endif
#endif
private:
@@ -262,6 +293,19 @@ struct Sphere final : public Primitive {
}
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
virtual void setOptixVariables(optix::Geometry geom, optix::Program bounds,
optix::Program intersect) const
{
geom->setPrimitiveCount(1u);
geom->setBoundingBoxProgram(bounds);
geom->setIntersectionProgram(intersect);
geom["sphere"]->setFloat(optix::make_float4(c.x, c.y, c.z, sqrtf(r2)));
geom["r2"]->setFloat(r2);
geom["a"]->setFloat(M_PIf * (r2 * r2));
}
# else
virtual void setOptixVariables(void* data) const
{
SphereParams* sphere_data = reinterpret_cast<SphereParams*>(data);
@@ -270,6 +314,7 @@ struct Sphere final : public Primitive {
sphere_data->a = M_PI * (r2 * r2);
sphere_data->shaderID = shaderid();
}
# endif
#endif
private:
@@ -361,6 +406,23 @@ struct Quad final : public Primitive {
}
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
virtual void setOptixVariables(optix::Geometry geom, optix::Program bounds,
optix::Program intersect) const
{
geom->setPrimitiveCount(1u);
geom->setBoundingBoxProgram(bounds);
geom->setIntersectionProgram(intersect);
geom["p"]->setFloat(vec3_to_float3(p));
geom["ex"]->setFloat(vec3_to_float3(ex));
geom["ey"]->setFloat(vec3_to_float3(ey));
geom["n"]->setFloat(vec3_to_float3(n));
geom["eu"]->setFloat(eu);
geom["ev"]->setFloat(ev);
geom["a"]->setFloat(a);
}
# else
virtual void setOptixVariables(void* data) const
{
QuadParams* quad_data = reinterpret_cast<QuadParams*>(data);
@@ -373,6 +435,7 @@ struct Quad final : public Primitive {
quad_data->a = a;
quad_data->shaderID = shaderid();
}
# endif
#endif
private:
@@ -472,6 +535,11 @@ struct Scene {
std::vector<Sphere> spheres;
std::vector<Quad> quads;
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
std::vector<optix::Material> optix_mtls;
# endif
#endif
};
OSL_NAMESPACE_EXIT
+1 -15
View File
@@ -1,10 +1,6 @@
#pragma once
#include "optix_compat.h"
#if defined(OSL_USE_OPTIX) || defined(__CUDA_ARCH__)
#if (OPTIX_VERSION >= 70000)
struct RenderParams {
float3 bad_color;
float3 bg_color;
@@ -35,22 +31,16 @@ struct RenderParams {
uint64_t test_str_2;
};
struct PrimitiveParams {
float a; // area
unsigned int shaderID;
};
struct SphereParams : PrimitiveParams {
float3 c; // center
float r2; // radius ^2
};
struct QuadParams : PrimitiveParams {
float3 p;
float3 ex;
@@ -60,15 +50,11 @@ struct QuadParams : PrimitiveParams {
float ev;
};
struct GenericData {
void* data;
unsigned int sbtGeoIndex;
};
struct GenericRecord {
__align__(
OPTIX_SBT_RECORD_ALIGNMENT) char header[OPTIX_SBT_RECORD_HEADER_SIZE];
+5 -4
View File
@@ -154,10 +154,11 @@ struct MxConductorParams : public MxMicrofacetBaseParams {
Color3 evalT(float cos_theta) const { return Color3(0.0f); }
float get_ior() const
{
return 0; // no transmission possible
}
// Avoid function was declared but never referenced
// float get_ior() const
// {
// return 0; // no transmission possible
// }
};
struct MxGeneralizedSchlickParams : public MxMicrofacetBaseParams {
+12 -6
View File
@@ -823,6 +823,7 @@ SimpleRaytracer::globals_from_hit(ShaderGlobals& sg, const Ray& r,
sg.N = -sg.N;
sg.Ng = -sg.Ng;
}
sg.raytype = r.raytype;
sg.flipHandedness = sg.dPdx.cross(sg.dPdy).dot(sg.N) < 0;
// In our SimpleRaytracer, the "renderstate" itself just a pointer to
@@ -831,13 +832,16 @@ SimpleRaytracer::globals_from_hit(ShaderGlobals& sg, const Ray& r,
}
Vec3
SimpleRaytracer::eval_background(const Dual2<Vec3>& dir, ShadingContext* ctx)
SimpleRaytracer::eval_background(const Dual2<Vec3>& dir, ShadingContext* ctx,
int bounce)
{
ShaderGlobals sg;
memset((char*)&sg, 0, sizeof(ShaderGlobals));
sg.I = dir.val();
sg.dIdx = dir.dx();
sg.dIdy = dir.dy();
if (bounce >= 0)
sg.raytype = bounce > 0 ? Ray::DIFFUSE : Ray::CAMERA;
shadingsys->execute(*ctx, *m_shaders[backgroundShaderID], sg);
return process_background_closure(sg.Ci);
}
@@ -859,7 +863,7 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler,
if (!scene.intersect(r, t, id)) {
// we hit nothing? check background shader
if (backgroundShaderID >= 0) {
if (backgroundResolution > 0) {
if (b > 0 && backgroundResolution > 0) {
float bg_pdf = 0;
Vec3 bg = background.eval(r.direction, bg_pdf);
path_radiance
@@ -869,7 +873,7 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler,
} else {
// we aren't importance sampling the background - so just run it directly
path_radiance += path_weight
* eval_background(r.direction, ctx);
* eval_background(r.direction, ctx, b);
}
}
break;
@@ -931,7 +935,8 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler,
b.pdf);
if ((contrib.x + contrib.y + contrib.z) > 0) {
int shadow_id = id;
Ray shadow_ray = Ray(sg.P, bg_dir.val(), radius, 0);
Ray shadow_ray = Ray(sg.P, bg_dir.val(), radius, 0,
Ray::SHADOW);
Dual2<float> shadow_dist;
if (!scene.intersect(shadow_ray, shadow_dist,
shadow_id)) // ray reached the background?
@@ -956,7 +961,7 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler,
* MIS::power_heuristic<MIS::EVAL_WEIGHT>(light_pdf,
b.pdf);
if ((contrib.x + contrib.y + contrib.z) > 0) {
Ray shadow_ray = Ray(sg.P, ldir, radius, 0);
Ray shadow_ray = Ray(sg.P, ldir, radius, 0, Ray::SHADOW);
// trace a shadow ray and see if we actually hit the target
// in this tiny renderer, tracing a ray is probably cheaper than evaluating the light shader
int shadow_id = id; // ignore self hit
@@ -979,7 +984,8 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler,
// trace indirect ray and continue
BSDF::Sample p = result.bsdf.sample(-sg.I, xi, yi, zi);
path_weight *= p.weight;
bsdf_pdf = p.pdf;
bsdf_pdf = p.pdf;
r.raytype = Ray::DIFFUSE; // FIXME? Use DIFFUSE for all indiirect rays
r.direction = p.wi;
r.radius = radius;
// Just simply use roughness as spread slope
+4 -3
View File
@@ -109,7 +109,7 @@ private:
float m_screen_window[4];
int backgroundShaderID = -1;
int backgroundResolution = 0;
int backgroundResolution = 1024;
int aa = 1;
int max_bounces = 1000000;
int rr_depth = 5;
@@ -132,7 +132,7 @@ private:
typedef bool (SimpleRaytracer::*AttrGetter)(ShaderGlobals* sg, bool derivs,
ustring object, TypeDesc type,
ustring name, void* val);
typedef std::unordered_map<ustring, AttrGetter> AttrGetterMap;
typedef std::unordered_map<ustring, AttrGetter, ustringHash> AttrGetterMap;
AttrGetterMap m_attr_getters;
// Attribute getters
@@ -166,7 +166,8 @@ private:
// CPU renderer helpers
void globals_from_hit(ShaderGlobals& sg, const Ray& r,
const Dual2<float>& t, int id);
Vec3 eval_background(const Dual2<Vec3>& dir, ShadingContext* ctx);
Vec3 eval_background(const Dual2<Vec3>& dir, ShadingContext* ctx,
int bounce = -1);
Color3 subpixel_radiance(float x, float y, Sampler& sampler,
ShadingContext* ctx);
Color3 antialias_pixel(int x, int y, ShadingContext* ctx);
+113 -100
View File
@@ -21,13 +21,16 @@
#include <OpenImageIO/thread.h>
#include <OpenImageIO/timer.h>
#ifdef OSL_USE_OPTIX
// purely to get optix version -- once optix 7.0 is required this can go away
# include <optix.h>
#endif
#include <OSL/oslexec.h>
#include "optixraytracer.h"
#include "shading.h"
#include "simpleraytracer.h"
#ifdef OSL_USE_OPTIX
# include "optixraytracer.h"
#endif
using namespace OSL;
@@ -101,6 +104,11 @@ set_shadingsys_options()
shadingsys->attribute("llvm_debugging_symbols", 1);
shadingsys->attribute("llvm_profiling_events", 1);
// We rely on the default set of "raytypes" tags. To use a custom set,
// this is where we would do:
// shadingsys->attribute("raytypes", TypeDesc(TypeDesc::STRING, num_raytypes),
// raytype_names);
shadingsys_options_set = true;
}
@@ -215,119 +223,124 @@ main(int argc, const char* argv[])
OIIO::simd::set_denorms_zero_mode(false);
#endif
using namespace OIIO;
Timer timer;
// Read command line arguments
getargs(argc, argv);
// Allow magic env variable TESTRENDER_AA to override the --aa option,
// this is helpful for certain CI tests in special debug modes that would
// be too slow to be practical.
int aaoverride = OIIO::Strutil::stoi(
OIIO::Sysutil::getenv("TESTRENDER_AA"));
if (aaoverride)
aa = aaoverride;
SimpleRaytracer* rend = nullptr;
#ifdef OSL_USE_OPTIX
if (use_optix)
rend = new OptixRaytracer;
else
#if (OPTIX_VERSION < 70000)
try {
#endif
rend = new SimpleRaytracer;
using namespace OIIO;
Timer timer;
// Other renderer and global options
if (debug1 || verbose)
rend->errhandler().verbosity(ErrorHandler::VERBOSE);
rend->attribute("saveptx", (int)saveptx);
rend->attribute("max_bounces", max_bounces);
rend->attribute("rr_depth", rr_depth);
rend->attribute("aa", aa);
rend->attribute("show_albedo_scale", show_albedo_scale);
OIIO::attribute("threads", num_threads);
// Read command line arguments
getargs(argc, argv);
// Create a new shading system. We pass it the RendererServices
// object that services callbacks from the shading system, the
// TextureSystem (note: passing nullptr just makes the ShadingSystem
// make its own TS), and an error handler.
shadingsys = new ShadingSystem(rend, nullptr, &rend->errhandler());
rend->shadingsys = shadingsys;
SimpleRaytracer* rend = nullptr;
if (use_optix)
rend = new OptixRaytracer;
else
rend = new SimpleRaytracer;
// Register the layout of all closures known to this renderer
// Any closure used by the shader which is not registered, or
// registered with a different number of arguments will lead
// to a runtime error.
register_closures(shadingsys);
// Other renderer and global options
if (debug1 || verbose)
rend->errhandler().verbosity(ErrorHandler::VERBOSE);
rend->attribute("saveptx", (int)saveptx);
rend->attribute("max_bounces", max_bounces);
rend->attribute("rr_depth", rr_depth);
rend->attribute("aa", aa);
rend->attribute("show_albedo_scale", show_albedo_scale);
OIIO::attribute("threads", num_threads);
// Setup common attributes
set_shadingsys_options();
// Create a new shading system. We pass it the RendererServices
// object that services callbacks from the shading system, the
// TextureSystem (note: passing nullptr just makes the ShadingSystem
// make its own TS), and an error handler.
shadingsys = new ShadingSystem(rend, nullptr, &rend->errhandler());
rend->shadingsys = shadingsys;
// Register the layout of all closures known to this renderer
// Any closure used by the shader which is not registered, or
// registered with a different number of arguments will lead
// to a runtime error.
register_closures(shadingsys);
// Setup common attributes
set_shadingsys_options();
#ifdef OSL_USE_OPTIX
if (use_optix)
reinterpret_cast<OptixRaytracer*>(rend)->synch_attributes();
# if (OPTIX_VERSION >= 70000)
if (use_optix)
reinterpret_cast<OptixRaytracer*>(rend)->synch_attributes();
# endif
#endif
// Loads a scene, creating camera, geometry and assigning shaders
rend->camera.resolution(xres, yres);
rend->parse_scene_xml(scenefile);
// Loads a scene, creating camera, geometry and assigning shaders
rend->camera.resolution(xres, yres);
rend->parse_scene_xml(scenefile);
rend->prepare_render();
rend->prepare_render();
rend->pixelbuf.reset(ImageSpec(xres, yres, 3, TypeDesc::FLOAT));
rend->pixelbuf.reset(ImageSpec(xres, yres, 3, TypeDesc::FLOAT));
double setuptime = timer.lap();
double setuptime = timer.lap();
if (warmup)
rend->warmup();
double warmuptime = timer.lap();
if (warmup)
rend->warmup();
double warmuptime = timer.lap();
// Launch the kernel to render the scene
for (int i = 0; i < iters; ++i)
rend->render(xres, yres);
double runtime = timer.lap();
// Launch the kernel to render the scene
for (int i = 0; i < iters; ++i)
rend->render(xres, yres);
double runtime = timer.lap();
rend->finalize_pixel_buffer();
rend->finalize_pixel_buffer();
// Write image to disk
if (Strutil::iends_with(imagefile, ".jpg")
|| Strutil::iends_with(imagefile, ".jpeg")
|| Strutil::iends_with(imagefile, ".gif")
|| Strutil::iends_with(imagefile, ".png")) {
// JPEG, GIF, and PNG images should be automatically saved as sRGB
// because they are almost certainly supposed to be displayed on web
// pages.
ImageBufAlgo::colorconvert(rend->pixelbuf, rend->pixelbuf, "linear",
"sRGB", false, "", "");
// Write image to disk
if (Strutil::iends_with(imagefile, ".jpg")
|| Strutil::iends_with(imagefile, ".jpeg")
|| Strutil::iends_with(imagefile, ".gif")
|| Strutil::iends_with(imagefile, ".png")) {
// JPEG, GIF, and PNG images should be automatically saved as sRGB
// because they are almost certainly supposed to be displayed on web
// pages.
ImageBufAlgo::colorconvert(rend->pixelbuf, rend->pixelbuf, "linear",
"sRGB", false, "", "");
}
rend->pixelbuf.set_write_format(TypeDesc::HALF);
if (!rend->pixelbuf.write(imagefile))
rend->errhandler().errorfmt("Unable to write output image: {}",
rend->pixelbuf.geterror());
double writetime = timer.lap();
// Print some debugging info
if (debug1 || runstats || profile) {
std::cout << "\n";
std::cout << "Setup : "
<< OIIO::Strutil::timeintervalformat(setuptime, 4)
<< "\n";
std::cout << "Warmup: "
<< OIIO::Strutil::timeintervalformat(warmuptime, 4)
<< "\n";
std::cout << "Run : "
<< OIIO::Strutil::timeintervalformat(runtime, 4) << "\n";
std::cout << "Write : "
<< OIIO::Strutil::timeintervalformat(writetime, 4)
<< "\n";
std::cout << "\n";
std::cout << shadingsys->getstats(5) << "\n";
OIIO::TextureSystem* texturesys = shadingsys->texturesys();
if (texturesys)
std::cout << texturesys->getstats(5) << "\n";
std::cout << ustring::getstats() << "\n";
}
// We're done with the shading system now, destroy it
rend->clear();
delete shadingsys;
delete rend;
#if (OPTIX_VERSION < 70000)
} catch (const OSL::optix::Exception& e) {
OSL::print("Optix Error: {}\n", e.what());
} catch (const std::exception& e) {
OSL::print("Unknown Error: {}\n", e.what());
}
rend->pixelbuf.set_write_format(TypeDesc::HALF);
if (!rend->pixelbuf.write(imagefile))
rend->errhandler().errorfmt("Unable to write output image: {}",
rend->pixelbuf.geterror());
double writetime = timer.lap();
// Print some debugging info
if (debug1 || runstats || profile) {
std::cout << "\n";
std::cout << "Setup : "
<< OIIO::Strutil::timeintervalformat(setuptime, 4) << "\n";
std::cout << "Warmup: "
<< OIIO::Strutil::timeintervalformat(warmuptime, 4) << "\n";
std::cout << "Run : " << OIIO::Strutil::timeintervalformat(runtime, 4)
<< "\n";
std::cout << "Write : "
<< OIIO::Strutil::timeintervalformat(writetime, 4) << "\n";
std::cout << "\n";
std::cout << shadingsys->getstats(5) << "\n";
OIIO::TextureSystem* texturesys = shadingsys->texturesys();
if (texturesys)
std::cout << texturesys->getstats(5) << "\n";
std::cout << ustring::getstats() << "\n";
}
// We're done with the shading system now, destroy it
rend->clear();
delete shadingsys;
delete rend;
#endif
return EXIT_SUCCESS;
}
+42 -43
View File
@@ -3,21 +3,29 @@
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
# The 'testshade' executable
set ( testshade_srcs
testshade.cpp
simplerend.cpp )
set ( testshade_srcs
testshade.cpp
simplerend.cpp
optixgridrender.cpp
../testrender/optix_stringtable.cpp )
if (BUILD_BATCHED)
list(APPEND testshade_srcs
batched_simplerend.cpp)
batched_simplerend.cpp
)
endif()
if (USE_OPTIX)
list (APPEND testshade_srcs optixgridrender.cpp)
set ( testshade_cuda_srcs
cuda/optix_grid_renderer.cu
../testrender/cuda/wrapper.cu
../testrender/cuda/rend_lib.cu )
../testrender/cuda/wrapper.cu )
# We only need to generate the PTX for rend_lib.cu if we are using OptiX 7.0+.
# Some of OptiX 6 device functions defined in rend_lib.cu cannot be compiled
# with NVCC, they must be compiled with clang using the LLVM_COMPILE_CUDA macro.
if (OPTIX_VERSION VERSION_GREATER_EQUAL 7)
list (APPEND testshade_cuda_srcs ../testrender/cuda/rend_lib.cu)
endif ()
set ( testshade_cuda_headers
../testrender/cuda/rend_lib.h )
@@ -62,42 +70,33 @@ target_link_libraries (testshade
PRIVATE
oslexec oslquery)
install (TARGETS testshade RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
# The 'libtestshade' library
add_library ( "libtestshade" ${testshade_srcs} )
set_target_properties (libtestshade
PROPERTIES
VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
SOVERSION ${SOVERSION}
OUTPUT_NAME libtestshade${OSL_LIBNAME_SUFFIX}
)
target_link_libraries (libtestshade
PRIVATE
oslexec oslquery)
set_target_properties (libtestshade PROPERTIES PREFIX "")
install_targets ( libtestshade )
# The 'testshade_dso' executable
add_executable ( testshade_dso testshade_dso.cpp )
target_link_libraries (testshade_dso
PRIVATE
OpenImageIO::OpenImageIO
${Boost_LIBRARIES} ${CMAKE_DL_LIBS} )
install (TARGETS testshade_dso RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
osl_optix_target(testshade)
# As explained in PR #39, problems were reported with calling OSL from a
# Houdini plugin. So this section sets up a version of testshade as a DSO, to
# be sure we can link it into an executable properly.
#
# But the fact that we use testshade.cpp twice -- once for regular testshade,
# once for the DSO version -- is throwing off the code coverage test, so at
# least for now, disable the dso version entirely when CODECOV is on.
if (NOT CODECOV)
# The 'libtestshade' library
add_library ( "libtestshade" ${testshade_srcs} )
set_target_properties (libtestshade
PROPERTIES
VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
SOVERSION ${SOVERSION}
OUTPUT_NAME libtestshade${OSL_LIBNAME_SUFFIX}
)
target_link_libraries (libtestshade
PRIVATE
oslexec oslquery)
set_target_properties (libtestshade PROPERTIES PREFIX "")
install_targets ( libtestshade )
# The 'testshade_dso' executable
add_executable ( testshade_dso testshade_dso.cpp )
target_link_libraries (testshade_dso
PRIVATE
OpenImageIO::OpenImageIO
${Boost_LIBRARIES} ${CMAKE_DL_LIBS} )
install (TARGETS testshade_dso RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
osl_optix_target(libtestshade)
endif ()
osl_optix_target(libtestshade)
+6 -4
View File
@@ -99,8 +99,8 @@ public:
private:
SimpleRenderer& m_sr;
std::unordered_set<ustring> m_uniform_objects;
std::unordered_set<ustring> m_uniform_attributes;
std::unordered_set<ustring, ustringHash> m_uniform_objects;
std::unordered_set<ustring, ustringHash> m_uniform_attributes;
// Attribute and userdata retrieval -- for fast dispatch, use a hash
// table to map attribute names to functions that retrieve them. We
@@ -110,13 +110,15 @@ private:
typedef bool (BatchedSimpleRenderer::*VaryingAttrGetter)(ustring object,
ustring name,
MaskedData val);
typedef std::unordered_map<ustring, VaryingAttrGetter> VaryingAttrGetterMap;
typedef std::unordered_map<ustring, VaryingAttrGetter, ustringHash>
VaryingAttrGetterMap;
VaryingAttrGetterMap m_varying_attr_getters;
typedef bool (BatchedSimpleRenderer::*UniformAttrGetter)(ustring object,
ustring name,
RefData val);
typedef std::unordered_map<ustring, UniformAttrGetter> UniformAttrGetterMap;
typedef std::unordered_map<ustring, UniformAttrGetter, ustringHash>
UniformAttrGetterMap;
UniformAttrGetterMap m_uniform_attr_getters;
// Attribute getters
+94 -3
View File
@@ -5,13 +5,101 @@
#include <optix.h>
#include <optix_device.h>
#if (OPTIX_VERSION < 70000)
# include <optixu/optixu_math_namespace.h>
# include <optixu/optixu_vector_types.h>
#else
# include <optix_device.h>
#endif
#include "rend_lib.h"
#include "render_params.h"
#include <optix_device.h>
#if (OPTIX_VERSION < 70000)
using namespace optix;
// Launch variables
rtDeclareVariable(uint2, launch_index, rtLaunchIndex, );
rtDeclareVariable(uint2, launch_dim, rtLaunchDim, );
// Scene/Shading variables
rtDeclareVariable(float, invw, , );
rtDeclareVariable(float, invh, , );
rtDeclareVariable(int, flipv, , );
// Buffers
rtBuffer<float3, 2> output_buffer;
rtDeclareVariable(rtCallableProgramId<void(void*, void*)>, osl_init_func, , );
rtDeclareVariable(rtCallableProgramId<void(void*, void*)>, osl_group_func, , );
RT_PROGRAM void
raygen()
{
// Compute the pixel coordinates
float2 d = make_float2(static_cast<float>(launch_index.x) + 0.5f,
static_cast<float>(launch_index.y) + 0.5f);
// TODO: Fixed-sized allocations can easily be exceeded by arbitrary shader
// networks, so there should be (at least) some mechanism to issue a
// warning or error if the closure or param storage can possibly be
// exceeded.
alignas(8) char closure_pool[256];
alignas(8) char params[256];
ShaderGlobals sg;
// Setup the ShaderGlobals
sg.I = make_float3(0, 0, 1);
sg.N = make_float3(0, 0, 1);
sg.Ng = make_float3(0, 0, 1);
sg.P = make_float3(d.x, d.y, 0);
sg.u = d.x * invw;
sg.v = d.y * invh;
if (flipv)
sg.v = 1.f - sg.v;
sg.dudx = invw;
sg.dudy = 0;
sg.dvdx = 0;
sg.dvdy = invh;
sg.dPdu = make_float3(d.x, 0, 0);
sg.dPdv = make_float3(0, d.y, 0);
sg.dPdu = make_float3(1.f / invw, 0.f, 0.f);
sg.dPdv = make_float3(0.0f, 1.f / invh, 0.f);
sg.dPdx = make_float3(1.f, 0.f, 0.f);
sg.dPdy = make_float3(0.f, 1.f, 0.f);
sg.dPdz = make_float3(0.f, 0.f, 0.f);
sg.Ci = NULL;
sg.surfacearea = 0;
sg.backfacing = 0;
// NB: These variables are not used in the current iteration of the sample
sg.raytype = CAMERA;
sg.flipHandedness = 0;
// Pack the "closure pool" into one of the ShaderGlobals pointers
*(int*)&closure_pool[0] = 0;
sg.renderstate = &closure_pool[0];
// Run the OSL group and init functions
osl_init_func(&sg, params);
osl_group_func(&sg, params);
float* output = (float*)params;
output_buffer[launch_index] = { output[1], output[2], output[3] };
}
#else //#if (OPTIX_VERSION < 70000)
# include "render_params.h"
# include <optix_device.h>
extern "C" {
@@ -146,3 +234,6 @@ osl_tex2DLookup(void* handle, float s, float t)
cudaTextureObject_t texID = cudaTextureObject_t(handle);
return tex2D<float4>(texID, s, t);
}
#endif //#if (OPTIX_VERSION < 70000)
+492 -132
View File
@@ -13,11 +13,15 @@
#include "render_params.h"
#include <cuda.h>
#include <nvrtc.h>
#include <optix_function_table_definition.h>
#include <optix_stack_size.h>
#include <optix_stubs.h>
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION >= 70000)
# include <cuda.h>
# include <nvrtc.h>
# include <optix_function_table_definition.h>
# include <optix_stack_size.h>
# include <optix_stubs.h>
# endif
#endif
// The pre-compiled renderer support library LLVM bitcode is embedded
// into the executable and made available through these variables.
@@ -29,40 +33,34 @@ extern unsigned char rend_llvm_compiled_ops_block[];
OSL_NAMESPACE_ENTER
#define CUDA_CHECK(call) \
{ \
cudaError_t res = call; \
if (res != cudaSuccess) { \
print(stderr, \
"[CUDA ERROR] Cuda call '{}' failed with error:" \
" {} ({}:{})\n", \
#call, cudaGetErrorString(res), __FILE__, __LINE__); \
} \
}
#if (OPTIX_VERSION >= 70000)
#define OPTIX_CHECK(call) \
{ \
OptixResult res = call; \
if (res != OPTIX_SUCCESS) { \
print(stderr, \
"[OPTIX ERROR] OptiX call '{}' failed with error:" \
" {} ({}:{})\n", \
#call, optixGetErrorName(res), __FILE__, __LINE__); \
exit(1); \
} \
}
# define CUDA_CHECK(call) \
{ \
cudaError_t error = call; \
if (error != cudaSuccess) { \
std::stringstream ss; \
ss << "CUDA call (" << #call << " ) failed with error: '" \
<< cudaGetErrorString(error) << "' (" __FILE__ << ":" \
<< __LINE__ << ")\n"; \
print(stderr, "[CUDA ERROR] {}", ss.str()); \
exit(1); \
} \
}
#define OPTIX_CHECK_MSG(call, msg) \
{ \
OptixResult res = call; \
if (res != OPTIX_SUCCESS) { \
print(stderr, \
"[OPTIX ERROR] OptiX call '{}' failed with error:" \
" {} ({}:{})\nMessage: {}\n", \
#call, optixGetErrorName(res), __FILE__, __LINE__, msg); \
exit(1); \
} \
}
# define OPTIX_CHECK(call) \
{ \
OptixResult res = call; \
if (res != OPTIX_SUCCESS) { \
std::stringstream ss; \
ss << "Optix call '" << #call \
<< "' failed with error: " << optixGetErrorName(res) \
<< " (" __FILE__ ":" << __LINE__ << ")\n"; \
print(stderr, "[OPTIX ERROR] {}", ss.str()); \
exit(1); \
} \
}
#endif
#define CUDA_SYNC_CHECK() \
{ \
@@ -75,18 +73,32 @@ OSL_NAMESPACE_ENTER
} \
}
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION >= 70000)
static void
context_log_cb(unsigned int level, const char* tag, const char* message,
void* /*cbdata */)
{
// std::cerr << "[" << std::setw( 2 ) << level << "][" << std::setw( 12 ) << tag << "]: " << message << "\n";
}
# endif
#endif
OptixGridRenderer::OptixGridRenderer()
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
// Set up the OptiX context
m_optix_ctx = optix::Context::create();
if (m_optix_ctx->getEnabledDeviceCount() != 1)
errhandler().warning("Only one CUDA device is currently supported");
// Set up the string table. This allocates a block of CUDA device memory to
// hold all of the static strings used by the OSL shaders. The strings can
// be accessed via OptiX variables that hold pointers to the table entries.
m_str_table.init(m_optix_ctx);
# else
// Initialize CUDA
cudaFree(0);
@@ -101,10 +113,17 @@ OptixGridRenderer::OptixGridRenderer()
CUDA_CHECK(cudaSetDevice(0));
CUDA_CHECK(cudaStreamCreate(&m_cuda_stream));
# define STRDECL(str, var_name) \
register_string(str, OSL_NAMESPACE_STRING \
"::DeviceStrings::" #var_name);
# include <OSL/strdecls.h>
# undef STRDECL
# endif //#if (OPTIX_VERSION < 70000)
#endif //#ifdef OSL_USE_OPTIX
}
uint64_t
OptixGridRenderer::register_global(const std::string& str, uint64_t value)
{
@@ -117,8 +136,6 @@ OptixGridRenderer::register_global(const std::string& str, uint64_t value)
return value;
}
bool
OptixGridRenderer::fetch_global(const std::string& str, uint64_t* value)
{
@@ -136,6 +153,7 @@ OptixGridRenderer::fetch_global(const std::string& str, uint64_t* value)
std::string
OptixGridRenderer::load_ptx_file(string_view filename)
{
#ifdef OSL_USE_OPTIX
std::vector<std::string> paths
= { OIIO::Filesystem::parent_path(OIIO::Sysutil::this_program_path()),
PTX_PATH };
@@ -146,6 +164,7 @@ OptixGridRenderer::load_ptx_file(string_view filename)
if (OIIO::Filesystem::read_text_file(filepath, ptx_string))
return ptx_string;
}
#endif
errhandler().severefmt("Unable to load {}", filename);
return {};
}
@@ -154,10 +173,18 @@ OptixGridRenderer::load_ptx_file(string_view filename)
OptixGridRenderer::~OptixGridRenderer()
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
m_str_table.freetable();
if (m_optix_ctx)
m_optix_ctx->destroy();
# else
for (void* p : m_ptrs_to_free)
cudaFree(p);
if (m_optix_ctx)
OPTIX_CHECK(optixDeviceContextDestroy(m_optix_ctx));
# endif
#endif
}
@@ -166,6 +193,14 @@ void
OptixGridRenderer::init_shadingsys(ShadingSystem* ss)
{
shadingsys = ss;
#if defined(OSL_USE_OPTIX) && OPTIX_VERSION < 70000
// NB: renderers using OptiX7+ are expected to link to rend_lib.cu manually
// to avoid duplicate 'rend_lib' symbols in each shader group.
shadingsys->attribute("lib_bitcode",
{ OSL::TypeDesc::UINT8, rend_llvm_compiled_ops_size },
rend_llvm_compiled_ops_block);
#endif
}
@@ -174,6 +209,26 @@ bool
OptixGridRenderer::init_optix_context(int xres OSL_MAYBE_UNUSED,
int yres OSL_MAYBE_UNUSED)
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
m_optix_ctx->setRayTypeCount(2);
m_optix_ctx->setEntryPointCount(1);
m_optix_ctx->setStackSize(2048);
m_optix_ctx->setPrintEnabled(true);
// Load the renderer CUDA source and generate PTX for it
std::string progName = "optix_grid_renderer.ptx";
std::string renderer_ptx = load_ptx_file(progName);
if (renderer_ptx.empty()) {
errhandler().severefmt("Could not find PTX for the raygen program");
return false;
}
// Create the OptiX programs and set them on the optix::Context
m_program = m_optix_ctx->createProgramFromPTXString(renderer_ptx, "raygen");
m_optix_ctx->setRayGenerationProgram(0, m_program);
# endif //#if (OPTIX_VERSION < 70000)
#endif
return true;
}
@@ -182,6 +237,86 @@ OptixGridRenderer::init_optix_context(int xres OSL_MAYBE_UNUSED,
bool
OptixGridRenderer::synch_attributes()
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
// FIXME -- this is for testing only
// Make some device strings to test userdata parameters
uint64_t addr1 = register_string("ud_str_1", "");
uint64_t addr2 = register_string("userdata string", "");
m_optix_ctx["test_str_1"]->setUserData(sizeof(char*), &addr1);
m_optix_ctx["test_str_2"]->setUserData(sizeof(char*), &addr2);
m_optix_ctx["object2common"]->setMatrix4x4fv(/*transpose*/ false,
m_object2common.getValue());
m_optix_ctx["shader2common"]->setMatrix4x4fv(/*transpose*/ false,
m_shader2common.getValue());
{
const char* name = OSL_NAMESPACE_STRING "::pvt::s_color_system";
char* colorSys = nullptr;
long long cpuDataSizes[2] = { 0, 0 };
if (!shadingsys->getattribute("colorsystem", TypeDesc::PTR,
(void*)&colorSys)
|| !shadingsys->getattribute("colorsystem:sizes",
TypeDesc(TypeDesc::LONGLONG, 2),
(void*)&cpuDataSizes)
|| !colorSys || !cpuDataSizes[0]) {
errhandler().errorfmt("No colorsystem available.");
return false;
}
auto cpuDataSize = cpuDataSizes[0];
auto numStrings = cpuDataSizes[1];
// Get the size data-size, minus the ustring size
const size_t podDataSize = cpuDataSize
- sizeof(StringParam) * numStrings;
optix::Buffer buffer = m_optix_ctx->createBuffer(RT_BUFFER_INPUT,
RT_FORMAT_USER);
if (!buffer) {
errhandler().errorfmt("Could not create buffer for '{}'.", name);
return false;
}
// set the element size to char
buffer->setElementSize(sizeof(char));
// and number of elements to the actual size needed.
buffer->setSize(podDataSize + sizeof(DeviceString) * numStrings);
// copy the base data
char* gpuData = (char*)buffer->map();
if (!gpuData) {
errhandler().errorfmt("Could not map buffer for '{}' (size: {}).",
name,
podDataSize
+ sizeof(DeviceString) * numStrings);
return false;
}
::memcpy(gpuData, colorSys, podDataSize);
// then copy the device string to the end, first strings starting at dataPtr - (numStrings)
// FIXME -- Should probably handle alignment better.
const ustring* cpuString
= (const ustring*)(colorSys
+ (cpuDataSize
- sizeof(StringParam) * numStrings));
char* gpuStrings = gpuData + podDataSize;
for (const ustring* end = cpuString + numStrings; cpuString < end;
++cpuString) {
// convert the ustring to a device string
uint64_t devStr = register_string(cpuString->string(), "");
::memcpy(gpuStrings, &devStr, sizeof(devStr));
gpuStrings += sizeof(DeviceString);
}
buffer->unmap();
m_optix_ctx[name]->setBuffer(buffer);
# else // #if (OPTIX_VERSION < 70000)
// FIXME -- this is for testing only
// Make some device strings to test userdata parameters
ustring userdata_str1("ud_str_1");
@@ -245,12 +380,14 @@ OptixGridRenderer::synch_attributes()
for (const ustring* end = cpuString + numStrings; cpuString < end;
++cpuString) {
// convert the ustring to a device string
uint64_t devStr = cpuString->hash();
uint64_t devStr = register_string(cpuString->string(), "");
CUDA_CHECK(cudaMemcpy(reinterpret_cast<void*>(gpuStrings), &devStr,
sizeof(devStr), cudaMemcpyHostToDevice));
gpuStrings += sizeof(DeviceString);
}
# endif
}
#endif
return true;
}
@@ -259,6 +396,8 @@ OptixGridRenderer::synch_attributes()
bool
OptixGridRenderer::make_optix_materials()
{
#ifdef OSL_USE_OPTIX
// Stand-in: names of shader outputs to preserve
// FIXME
std::vector<const char*> outputs { "Cout" };
@@ -268,6 +407,63 @@ OptixGridRenderer::make_optix_materials()
// hit program in the wrapper to execute the compiled OSL shader.
int mtl_id = 0;
# if (OPTIX_VERSION < 70000)
for (const auto& groupref : shaders()) {
shadingsys->attribute(groupref.get(), "renderer_outputs",
TypeDesc(TypeDesc::STRING, outputs.size()),
outputs.data());
shadingsys->optimize_group(groupref.get(), nullptr);
if (!shadingsys->find_symbol(*groupref.get(), ustring(outputs[0]))) {
// FIXME: This is for cases where testshade is run with 1x1 resolution
// Those tests may not have a Cout parameter to write to.
if (m_xres > 1 && m_yres > 1) {
errhandler().warning("Requested output '%s', which wasn't found",
outputs[0]);
}
}
std::string group_name, init_name, entry_name;
shadingsys->getattribute(groupref.get(), "groupname", group_name);
shadingsys->getattribute(groupref.get(), "group_init_name", init_name);
shadingsys->getattribute(groupref.get(), "group_entry_name",
entry_name);
// Retrieve the compiled ShaderGroup PTX
std::string osl_ptx;
shadingsys->getattribute(groupref.get(), "ptx_compiled_version",
OSL::TypeDesc::PTR, &osl_ptx);
if (osl_ptx.empty()) {
errhandler().errorfmt("Failed to generate PTX for ShaderGroup {}",
group_name);
return false;
}
if (options.get_int("saveptx")) {
std::string filename
= OIIO::Strutil::fmt::format("{}_{}.ptx", group_name, mtl_id++);
OIIO::ofstream out;
OIIO::Filesystem::open(out, filename);
out << osl_ptx;
}
// Create Programs from the init and group_entry functions,
// and set the OSL functions as Callable Programs so that they
// can be executed by the closest hit program in the wrapper
optix::Program osl_init
= m_optix_ctx->createProgramFromPTXString(osl_ptx, init_name);
optix::Program osl_group
= m_optix_ctx->createProgramFromPTXString(osl_ptx, entry_name);
// Grid shading
m_program["osl_init_func"]->setProgramId(osl_init);
m_program["osl_group_func"]->setProgramId(osl_group);
}
# else //#if (OPTIX_VERSION < 70000)
std::vector<OptixModule> modules;
// Space for message logging
@@ -279,12 +475,12 @@ OptixGridRenderer::make_optix_materials()
module_compile_options.maxRegisterCount
= OPTIX_COMPILE_DEFAULT_MAX_REGISTER_COUNT;
module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT;
#if OPTIX_VERSION >= 70400
module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT;
# if OPTIX_VERSION >= 70400
module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_MINIMAL;
#else
# else
module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO;
#endif
# endif
OptixPipelineCompileOptions pipeline_compile_options = {};
@@ -309,13 +505,13 @@ OptixGridRenderer::make_optix_materials()
sizeof_msg_log = sizeof(msg_log);
OptixModule program_module;
OPTIX_CHECK_MSG(optixModuleCreateFromPTX(m_optix_ctx,
&module_compile_options,
&pipeline_compile_options,
program_ptx.c_str(),
program_ptx.size(), msg_log,
&sizeof_msg_log, &program_module),
fmtformat("Creating Module from PTX-file {}", msg_log));
OPTIX_CHECK(optixModuleCreateFromPTX(m_optix_ctx, &module_compile_options,
&pipeline_compile_options,
program_ptx.c_str(),
program_ptx.size(), msg_log,
&sizeof_msg_log, &program_module));
//if (sizeof_msg_log > 1)
// printf ("Creating module from PTX-file %s:\n%s\n", progName.c_str(), msg_log);
// Record it so we can destroy it later
modules.push_back(program_module);
@@ -331,12 +527,13 @@ OptixGridRenderer::make_optix_materials()
OptixProgramGroup raygen_group;
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(optixProgramGroupCreate(m_optix_ctx, &raygen_desc,
1, // number of program groups
&program_options, // program options
msg_log, &sizeof_msg_log,
&raygen_group),
fmtformat("Creating 'ray-gen' program group: {}", msg_log));
OPTIX_CHECK(optixProgramGroupCreate(m_optix_ctx, &raygen_desc,
1, // number of program groups
&program_options, // program options
msg_log, &sizeof_msg_log,
&raygen_group));
//if (sizeof_msg_log > 1)
// printf ("Creating 'ray-gen' program group:\n%s\n", msg_log);
// Set Globals Raygen group
OptixProgramGroupDesc setglobals_raygen_desc = {};
@@ -346,12 +543,13 @@ OptixGridRenderer::make_optix_materials()
OptixProgramGroup setglobals_raygen_group;
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(optixProgramGroupCreate(
m_optix_ctx, &setglobals_raygen_desc,
1, // number of program groups
&program_options, // program options
msg_log, &sizeof_msg_log, &setglobals_raygen_group),
fmtformat("Creating 'ray-gen' program group: {}", msg_log));
OPTIX_CHECK(optixProgramGroupCreate(m_optix_ctx, &setglobals_raygen_desc,
1, // number of program groups
&program_options, // program options
msg_log, &sizeof_msg_log,
&setglobals_raygen_group));
//if (sizeof_msg_log > 1)
// printf ("Creating set-globals 'ray-gen' program group:\n%s\n", msg_log);
// Miss group
OptixProgramGroupDesc miss_desc = {};
@@ -361,10 +559,11 @@ OptixGridRenderer::make_optix_materials()
OptixProgramGroup miss_group;
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(optixProgramGroupCreate(m_optix_ctx, &miss_desc, 1,
&program_options, msg_log,
&sizeof_msg_log, &miss_group),
fmtformat("Creating 'miss' program group: {}", msg_log));
OPTIX_CHECK(optixProgramGroupCreate(m_optix_ctx, &miss_desc, 1,
&program_options, msg_log,
&sizeof_msg_log, &miss_group));
//if (sizeof_msg_log > 1)
// printf ("Creating 'miss' program group:\n%s\n", msg_log);
// Set Globals Miss group
OptixProgramGroupDesc setglobals_miss_desc = {};
@@ -374,12 +573,12 @@ OptixGridRenderer::make_optix_materials()
OptixProgramGroup setglobals_miss_group;
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(optixProgramGroupCreate(m_optix_ctx, &setglobals_miss_desc,
1, &program_options, msg_log,
&sizeof_msg_log,
&setglobals_miss_group),
fmtformat("Creating set-globals 'miss' program group: {}",
msg_log));
OPTIX_CHECK(optixProgramGroupCreate(m_optix_ctx, &setglobals_miss_desc, 1,
&program_options, msg_log,
&sizeof_msg_log,
&setglobals_miss_group));
//if (sizeof_msg_log > 1)
// printf ("Creating set-globals 'miss' program group:\n%s\n", msg_log);
// Hitgroup
OptixProgramGroupDesc hitgroup_desc = {};
@@ -392,12 +591,13 @@ OptixGridRenderer::make_optix_materials()
OptixProgramGroup hitgroup_group;
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(
optixProgramGroupCreate(m_optix_ctx, &hitgroup_desc,
1, // number of program groups
&program_options, // program options
msg_log, &sizeof_msg_log, &hitgroup_group),
fmtformat("Creating 'hitgroup' program group: {}", msg_log));
OPTIX_CHECK(optixProgramGroupCreate(m_optix_ctx, &hitgroup_desc,
1, // number of program groups
&program_options, // program options
msg_log, &sizeof_msg_log,
&hitgroup_group));
//if (sizeof_msg_log > 1)
// printf ("Creating 'hitgroup' program group:\n%s\n", msg_log);
// Load the renderer support library CUDA source and generate PTX for it
std::string rendlibName = "rend_lib.ptx";
@@ -410,13 +610,13 @@ OptixGridRenderer::make_optix_materials()
// Create support library program group
sizeof_msg_log = sizeof(msg_log);
OptixModule rend_lib_module;
OPTIX_CHECK_MSG(optixModuleCreateFromPTX(m_optix_ctx,
&module_compile_options,
&pipeline_compile_options,
rend_lib_ptx.c_str(),
rend_lib_ptx.size(), msg_log,
&sizeof_msg_log, &rend_lib_module),
fmtformat("Creating module from PTX-file: {}", msg_log));
OPTIX_CHECK(optixModuleCreateFromPTX(m_optix_ctx, &module_compile_options,
&pipeline_compile_options,
rend_lib_ptx.c_str(),
rend_lib_ptx.size(), msg_log,
&sizeof_msg_log, &rend_lib_module));
//if (sizeof_msg_log > 1)
// printf ("Creating module from PTX-file %s:\n%s\n", progName.c_str(), msg_log);
// Record it so we can destroy it later
modules.push_back(rend_lib_module);
@@ -431,12 +631,13 @@ OptixGridRenderer::make_optix_materials()
rend_lib_desc.callables.entryFunctionNameCC = nullptr;
OptixProgramGroup rend_lib_group;
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(
optixProgramGroupCreate(m_optix_ctx, &rend_lib_desc,
1, // number of program groups
&program_options, // program options
msg_log, &sizeof_msg_log, &rend_lib_group),
fmtformat("Creating 'hitgroup' program group: {}", msg_log));
OPTIX_CHECK(optixProgramGroupCreate(m_optix_ctx, &rend_lib_desc,
1, // number of program groups
&program_options, // program options
msg_log, &sizeof_msg_log,
&rend_lib_group));
//if (sizeof_msg_log > 1)
// printf ("Creating 'hitgroup' program group:\n%s\n", msg_log);
// Create materials
for (const auto& groupref : shaders()) {
@@ -486,12 +687,13 @@ OptixGridRenderer::make_optix_materials()
// and set the OSL functions as Callable Programs so that they
// can be executed by the closest hit program in the wrapper
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(
OPTIX_CHECK(
optixModuleCreateFromPTX(m_optix_ctx, &module_compile_options,
&pipeline_compile_options, osl_ptx.c_str(),
osl_ptx.size(), msg_log, &sizeof_msg_log,
&optix_module),
fmtformat("Creating Module from PTX-file {}", msg_log));
&optix_module));
//if (sizeof_msg_log > 1)
// printf ("Creating module from PTX group '%s':\n%s\n", group_name.c_str(), msg_log);
modules.push_back(optix_module);
@@ -512,22 +714,23 @@ OptixGridRenderer::make_optix_materials()
program_groups.resize(program_groups.size() + 2);
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(
OPTIX_CHECK(
optixProgramGroupCreate(m_optix_ctx, &pgDesc[0],
2, // number of program groups
&program_options, // program options
msg_log, &sizeof_msg_log,
&program_groups[program_groups.size() - 2]),
fmtformat("Creating 'shader' group for group {}: {}", group_name,
msg_log));
&program_groups[program_groups.size() - 2]));
//if (sizeof_msg_log > 1)
// printf ("Creating 'shader' group for group '%s':\n%s\n", group_name.c_str(), msg_log);
}
OptixPipelineLinkOptions pipeline_link_options;
pipeline_link_options.maxTraceDepth = 1;
pipeline_link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL;
#if (OPTIX_VERSION < 70100)
# if (OPTIX_VERSION < 70100)
pipeline_link_options.overrideUsesMotionBlur = false;
#endif
# endif
// Set up OptiX pipeline
std::vector<OptixProgramGroup> final_groups = {
@@ -539,12 +742,12 @@ OptixGridRenderer::make_optix_materials()
};
sizeof_msg_log = sizeof(msg_log);
OPTIX_CHECK_MSG(optixPipelineCreate(m_optix_ctx, &pipeline_compile_options,
&pipeline_link_options,
final_groups.data(),
int(final_groups.size()), msg_log,
&sizeof_msg_log, &m_optix_pipeline),
fmtformat("Creating optix pipeline: {}", msg_log));
OPTIX_CHECK(optixPipelineCreate(m_optix_ctx, &pipeline_compile_options,
&pipeline_link_options, final_groups.data(),
int(final_groups.size()), msg_log,
&sizeof_msg_log, &m_optix_pipeline));
//if (sizeof_msg_log > 1)
// printf ("Creating optix pipeline:\n%s\n", msg_log);
// Set the pipeline stack size
OptixStackSizes stack_sizes = {};
@@ -656,6 +859,10 @@ OptixGridRenderer::make_optix_materials()
m_setglobals_optix_sbt.missRecordBase = d_setglobals_missRecord;
m_setglobals_optix_sbt.missRecordStrideInBytes = sizeof(EmptyRecord);
m_setglobals_optix_sbt.missRecordCount = 1;
# endif //#if (OPTIX_VERSION < 70000)
#endif //#ifdef OSL_USE_OPTIX
return true;
}
@@ -664,7 +871,34 @@ OptixGridRenderer::make_optix_materials()
bool
OptixGridRenderer::finalize_scene()
{
#ifdef OSL_USE_OPTIX
make_optix_materials();
# if (OPTIX_VERSION < 70000)
m_optix_ctx["invw"]->setFloat(1.0f / m_xres);
m_optix_ctx["invh"]->setFloat(1.0f / m_yres);
// Create the output buffer
optix::Buffer buffer = m_optix_ctx->createBuffer(RT_BUFFER_OUTPUT,
RT_FORMAT_FLOAT3, m_xres,
m_yres);
m_optix_ctx["output_buffer"]->set(buffer);
# else
# endif //#if (OPTIX_VERSION < 70000)
# if (OPTIX_VERSION < 70000)
if (!synch_attributes())
return false;
# endif
# if (OPTIX_VERSION < 70000)
m_optix_ctx->validate();
# else
# endif
#endif
return true;
}
@@ -676,7 +910,15 @@ OptixGridRenderer::finalize_scene()
bool
OptixGridRenderer::good(TextureHandle* handle OSL_MAYBE_UNUSED)
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
return intptr_t(handle) != RT_TEXTURE_ID_NULL;
# else
return handle != nullptr;
# endif
#else
return false;
#endif
}
@@ -688,6 +930,56 @@ OptixGridRenderer::get_texture_handle(ustring filename OSL_MAYBE_UNUSED,
ShadingContext* shading_context
OSL_MAYBE_UNUSED)
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
auto itr = m_samplers.find(filename);
if (itr == m_samplers.end()) {
optix::TextureSampler sampler = context()->createTextureSampler();
sampler->setWrapMode(0, RT_WRAP_REPEAT);
sampler->setWrapMode(1, RT_WRAP_REPEAT);
sampler->setWrapMode(2, RT_WRAP_REPEAT);
sampler->setFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR,
RT_FILTER_NONE);
sampler->setIndexingMode(false
? RT_TEXTURE_INDEX_ARRAY_INDEX
: RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
sampler->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
sampler->setMaxAnisotropy(1.0f);
OIIO::ImageBuf image;
if (!image.init_spec(filename, 0, 0)) {
errhandler().errorfmt("Could not load: {}", filename);
return (TextureHandle*)(intptr_t(RT_TEXTURE_ID_NULL));
}
int nchan = image.spec().nchannels;
OIIO::ROI roi = OIIO::get_roi_full(image.spec());
int width = roi.width(), height = roi.height();
std::vector<float> pixels(width * height * nchan);
image.get_pixels(roi, OIIO::TypeDesc::FLOAT, pixels.data());
optix::Buffer buffer = context()->createBuffer(RT_BUFFER_INPUT,
RT_FORMAT_FLOAT4, width,
height);
float* device_ptr = static_cast<float*>(buffer->map());
unsigned int pixel_idx = 0;
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
memcpy(device_ptr, &pixels[pixel_idx], sizeof(float) * nchan);
device_ptr += 4;
pixel_idx += nchan;
}
}
buffer->unmap();
sampler->setBuffer(buffer);
itr = m_samplers.emplace(std::move(filename), std::move(sampler)).first;
}
return (RendererServices::TextureHandle*)intptr_t(itr->second->getId());
# else //#if (OPTIX_VERSION < 70000)
auto itr = m_samplers.find(filename);
if (itr == m_samplers.end()) {
// Open image
@@ -746,6 +1038,12 @@ OptixGridRenderer::get_texture_handle(ustring filename OSL_MAYBE_UNUSED,
itr = m_samplers.emplace(std::move(filename), std::move(cuda_tex)).first;
}
return reinterpret_cast<RendererServices::TextureHandle*>(itr->second);
# endif //#if (OPTIX_VERSION < 70000)
#else
return nullptr;
#endif
}
@@ -753,11 +1051,13 @@ OptixGridRenderer::get_texture_handle(ustring filename OSL_MAYBE_UNUSED,
void
OptixGridRenderer::prepare_render()
{
#ifdef OSL_USE_OPTIX
// Set up the OptiX Context
init_optix_context(m_xres, m_yres);
// Set up the OptiX scene graph
finalize_scene();
#endif
}
@@ -765,10 +1065,17 @@ OptixGridRenderer::prepare_render()
void
OptixGridRenderer::warmup()
{
#ifdef OSL_USE_OPTIX
// Perform a tiny launch to warm up the OptiX context
# if (OPTIX_VERSION < 70000)
m_optix_ctx->launch(0, 1, 1);
# else
OPTIX_CHECK(optixLaunch(m_optix_pipeline, m_cuda_stream, d_launch_params,
sizeof(RenderParams), &m_optix_sbt, 0, 0, 1));
CUDA_SYNC_CHECK();
# endif
#endif
}
@@ -777,6 +1084,10 @@ OptixGridRenderer::warmup()
void
OptixGridRenderer::render(int xres OSL_MAYBE_UNUSED, int yres OSL_MAYBE_UNUSED)
{
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
m_optix_ctx->launch(0, xres, yres);
# else
CUDA_CHECK(cudaMalloc(reinterpret_cast<void**>(&d_output_buffer),
xres * yres * 4 * sizeof(float)));
CUDA_CHECK(cudaMalloc(reinterpret_cast<void**>(&d_launch_params),
@@ -828,10 +1139,12 @@ OptixGridRenderer::render(int xres OSL_MAYBE_UNUSED, int yres OSL_MAYBE_UNUSED)
OSL_PRINTF_BUFFER_SIZE, cudaMemcpyDeviceToHost));
processPrintfBuffer(printf_buffer.data(), OSL_PRINTF_BUFFER_SIZE);
# endif
#endif
}
#if defined(OSL_USE_OPTIX) && OPTIX_VERSION >= 70000
void
OptixGridRenderer::processPrintfBuffer(void* buffer_data, size_t buffer_size)
{
@@ -856,13 +1169,14 @@ OptixGridRenderer::processPrintfBuffer(void* buffer_data, size_t buffer_size)
// have we reached the end?
if (fmt_str_hash == 0)
break;
const char* format = ustring::from_hash(fmt_str_hash).c_str();
OSL_ASSERT(format != nullptr
&& "The string should have been a valid ustring");
const char* format = m_hash_map[fmt_str_hash];
OSL_ASSERT(
format != nullptr
&& "The format string should have been registered with the renderer");
const size_t len = strlen(format);
for (size_t j = 0; j < len; j++) {
// If we encounter a '%', then we'll copy the format string to 'fmt_string'
// If we encounter a '%', then we'l copy the format string to 'fmt_string'
// and provide that to printf() directly along with a pointer to the argument
// we're interested in printing.
if (format[j] == '%') {
@@ -874,7 +1188,7 @@ OptixGridRenderer::processPrintfBuffer(void* buffer_data, size_t buffer_size)
switch (format[j]) {
case '%':
// seems like a silly to print a '%', but it keeps the logic parallel with the other cases
dst += snprintf(&buffer[dst], BufferSize - dst,
dst += snprintf(&buffer[dst], BufferSize - dst, "%s",
fmt_string.c_str());
format_end_found = true;
break;
@@ -904,13 +1218,16 @@ OptixGridRenderer::processPrintfBuffer(void* buffer_data, size_t buffer_size)
format_end_found = true;
break;
case 's':
src = (src + sizeof(uint64_t) - 1)
& ~(sizeof(uint64_t) - 1);
src = (src + sizeof(double) - 1)
& ~(sizeof(double) - 1);
uint64_t str_hash = *reinterpret_cast<const uint64_t*>(
&ptr[src]);
ustring str = ustring::from_hash(str_hash);
const char* str = m_hash_map[str_hash];
OSL_ASSERT(
str != nullptr
&& "The string should have been regisgtered with the renderer");
dst += snprintf(&buffer[dst], BufferSize - dst,
fmt_string.c_str(), str.c_str());
fmt_string.c_str(), str);
src += sizeof(uint64_t);
format_end_found = true;
break;
@@ -930,13 +1247,22 @@ OptixGridRenderer::processPrintfBuffer(void* buffer_data, size_t buffer_size)
print("{}", buffer);
}
}
#endif
void
OptixGridRenderer::finalize_pixel_buffer()
{
#ifdef OSL_USE_OPTIX
std::string buffer_name = "output_buffer";
# if (OPTIX_VERSION < 70000)
const void* buffer_ptr = m_optix_ctx[buffer_name]->getBuffer()->map();
if (!buffer_ptr)
errhandler().severefmt("Unable to map buffer {}", buffer_name);
OIIO::ImageBuf* buf = outputbuf(0);
if (buf)
buf->set_pixels(OIIO::ROI::All(), OIIO::TypeFloat, buffer_ptr);
# else
std::vector<float> tmp_buff(m_xres * m_yres * 3);
CUDA_CHECK(cudaMemcpy(tmp_buff.data(),
reinterpret_cast<void*>(d_output_buffer),
@@ -945,6 +1271,8 @@ OptixGridRenderer::finalize_pixel_buffer()
OIIO::ImageBuf* buf = outputbuf(0);
if (buf)
buf->set_pixels(OIIO::ROI::All(), OIIO::TypeFloat, tmp_buff.data());
# endif
#endif
}
@@ -953,14 +1281,22 @@ void
OptixGridRenderer::clear()
{
shaders().clear();
#ifdef OSL_USE_OPTIX
# if (OPTIX_VERSION < 70000)
if (m_optix_ctx) {
m_optix_ctx->destroy();
m_optix_ctx = nullptr;
}
# else
if (m_optix_ctx) {
OPTIX_CHECK(optixDeviceContextDestroy(m_optix_ctx));
m_optix_ctx = 0;
}
# endif
#endif
}
void
OptixGridRenderer::set_transforms(const OSL::Matrix44& object2common,
const OSL::Matrix44& shader2common)
@@ -969,25 +1305,47 @@ OptixGridRenderer::set_transforms(const OSL::Matrix44& object2common,
m_shader2common = shader2common;
}
void
OptixGridRenderer::register_named_transforms()
{
#ifdef OSL_USE_OPTIX
std::vector<uint64_t> xform_name_buffer;
std::vector<OSL::Matrix44> xform_buffer;
// Gather:
// 1) All of the named transforms
// 2) The "string" value associated with the transform name, which is
// actually the ustring hash of the transform name.
// 2) The "string" value associated with the transform name:
// for OptiX 6, this is the address of the string variable;
// for OptiX 7+, this is the ustring hash of the transform name.
for (const auto& item : m_named_xforms) {
const uint64_t addr = item.first.hash();
const uint64_t addr
= OptixGridRenderer::register_string(item.first.c_str(), "");
xform_name_buffer.push_back(addr);
xform_buffer.push_back(*item.second);
}
// Push the names and transforms to the device
# if (OPTIX_VERSION < 70000)
optix::Buffer name_buffer
= m_optix_ctx->createBuffer(RT_BUFFER_INPUT,
RT_FORMAT_UNSIGNED_LONG_LONG,
xform_name_buffer.size());
uint64_t* names = reinterpret_cast<uint64_t*>(name_buffer->map());
memcpy(names, xform_name_buffer.data(),
sizeof(uint64_t) * xform_name_buffer.size());
name_buffer->unmap();
m_optix_ctx["xform_name_buffer"]->setBuffer(name_buffer);
optix::Buffer transform_buffer = m_optix_ctx->createBuffer(RT_BUFFER_INPUT);
transform_buffer->setFormat(RT_FORMAT_USER);
transform_buffer->setElementSize(sizeof(OSL::Matrix44));
transform_buffer->setSize(xform_buffer.size());
void* transforms = transform_buffer->map();
memcpy(transforms, xform_buffer.data(),
sizeof(OSL::Matrix44) * xform_buffer.size());
transform_buffer->unmap();
m_optix_ctx["xform_buffer"]->setBuffer(transform_buffer);
# else
size_t sz = sizeof(uint64_t) * xform_name_buffer.size();
CUDA_CHECK(cudaMalloc(reinterpret_cast<void**>(&d_xform_name_buffer), sz));
CUDA_CHECK(cudaMemcpy(reinterpret_cast<void*>(d_xform_name_buffer),
@@ -1002,6 +1360,8 @@ OptixGridRenderer::register_named_transforms()
m_ptrs_to_free.push_back(reinterpret_cast<void*>(d_xform_buffer));
m_num_named_xforms = xform_name_buffer.size();
# endif // if (OPTIX_VERSION < 70000)
#endif // ifdef OSL_USE_OPTIX
}
OSL_NAMESPACE_EXIT
+60 -10
View File
@@ -12,7 +12,9 @@
#include "optix_compat.h"
#include "simplerend.h"
#if OPTIX_VERSION < 70000
# include "../testrender/optix_stringtable.h"
#endif
OSL_NAMESPACE_ENTER
@@ -25,6 +27,22 @@ public:
OptixGridRenderer();
virtual ~OptixGridRenderer();
uint64_t register_string(const std::string& str,
const std::string& var_name)
{
ustring ustr = ustring(str);
#if OPTIX_VERSION < 70000
uint64_t addr = m_str_table.addString(ustr, ustring(var_name));
if (!var_name.empty()) {
register_global(var_name, addr);
}
return addr;
#else
m_hash_map[ustr.hash()] = ustr.c_str();
return static_cast<uint64_t>(ustr.hash());
#endif
}
uint64_t register_global(const std::string& str, uint64_t value);
bool fetch_global(const std::string& str, uint64_t* value);
@@ -63,19 +81,48 @@ public:
virtual TextureHandle* get_texture_handle(ustring filename,
ShadingContext* shading_context);
OptixDeviceContext optix_ctx() { return m_optix_ctx; }
OptixDeviceContext context() { return m_optix_ctx; }
OptixDeviceContext operator->() { return context(); }
#if (OPTIX_VERSION < 70000)
// Easy way to do Optix calls
optix::Context& optix_ctx()
{
return m_optix_ctx;
}
optix::Context& context()
{
return m_optix_ctx;
}
optix::Context& operator->()
{
return context();
}
#else
OptixDeviceContext optix_ctx()
{
return m_optix_ctx;
}
OptixDeviceContext context()
{
return m_optix_ctx;
}
OptixDeviceContext operator->()
{
return context();
}
void processPrintfBuffer(void* buffer_data, size_t buffer_size);
#endif
private:
optix::Context m_optix_ctx = nullptr;
#if (OPTIX_VERSION < 70000)
OptiXStringTable m_str_table;
optix::Program m_program = nullptr;
#else
CUstream m_cuda_stream;
OptixShaderBindingTable m_optix_sbt = {};
OptixShaderBindingTable m_optix_sbt = {};
OptixShaderBindingTable m_setglobals_optix_sbt = {};
OptixPipeline m_optix_pipeline = {};
OptixPipeline m_optix_pipeline = {};
CUdeviceptr d_output_buffer;
CUdeviceptr d_launch_params = 0;
CUdeviceptr d_osl_printf_buffer;
@@ -89,9 +136,12 @@ private:
uint64_t test_str_2;
const unsigned long OSL_PRINTF_BUFFER_SIZE = 8 * 1024 * 1024;
std::unordered_map<uint64_t, const char*> m_hash_map;
#endif
std::string m_materials_ptx;
std::unordered_map<OIIO::ustring, optix::TextureSampler> m_samplers;
std::unordered_map<OIIO::ustring, uint64_t> m_globals_map;
std::unordered_map<OIIO::ustring, optix::TextureSampler, OIIO::ustringHash>
m_samplers;
std::unordered_map<OIIO::ustring, uint64_t, OIIO::ustringHash> m_globals_map;
OSL::Matrix44 m_shader2common; // "shader" space to "common" space matrix
OSL::Matrix44 m_object2common; // "object" space to "common" space matrix
@@ -100,12 +150,12 @@ private:
std::vector<void*> m_ptrs_to_free;
};
#if (OPTIX_VERSION >= 70000)
struct EmptyRecord {
__align__(
OPTIX_SBT_RECORD_ALIGNMENT) char header[OPTIX_SBT_RECORD_HEADER_SIZE];
void* data;
};
#endif
OSL_NAMESPACE_EXIT
+1 -1
View File
@@ -18,7 +18,7 @@
// to utilize the RS_ prefix. RS_ prefixed versions of all OSL::Strings
// instances have been created by rs_free_function.h, so the same STRING_PARAMS
// macro can be used for renderer service or OSL strings.
#define RS_STRDECL(str, var_name) extern "C" OSL::ustring RS_##var_name;
#define RS_STRDECL(str, var_name) extern "C" const OSL::ustring RS_##var_name;
#include "rs_strdecls.h"
#undef RS_STRDECL

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