Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0be867f7bf | ||
|
|
362b01ecdd | ||
|
|
657dab9da0 | ||
|
|
26ad18688d | ||
|
|
a5857c5525 | ||
|
|
e2a3153667 | ||
|
|
34fa5c3755 | ||
|
|
67a3c0b93c | ||
|
|
60dcec97e7 | ||
|
|
cf47571daa | ||
|
|
c9672c8a0d | ||
|
|
e8fce16d36 | ||
|
|
76f187e4d0 | ||
|
|
7678df2971 | ||
|
|
9ffb5fb2a3 | ||
|
|
f61edf2fdf | ||
|
|
b2190faa27 | ||
|
|
35aa264dc8 | ||
|
|
5c1617fec2 | ||
|
|
f1c2299ff7 | ||
|
|
c7aee41a1c | ||
|
|
79ab666246 | ||
|
|
c8b59032fb | ||
|
|
0a9070cb62 | ||
|
|
80dee64963 | ||
|
|
901bea3aac | ||
|
|
b7a1a87dc7 | ||
|
|
0c60a1a170 | ||
|
|
98cc66a2e2 | ||
|
|
5592be9f11 | ||
|
|
517d10934f | ||
|
|
8ac55309ab | ||
|
|
c882e823c1 | ||
|
|
a5777fddc5 | ||
|
|
c14bcd2785 | ||
|
|
a23c42fcc6 | ||
|
|
434f04d336 | ||
|
|
a1002c61c1 | ||
|
|
92b0135971 | ||
|
|
3896d22a21 | ||
|
|
500381cc64 | ||
|
|
b2b5e5eaba | ||
|
|
8e420b4bc8 | ||
|
|
a90ed53f88 | ||
|
|
7ee3e36dbb | ||
|
|
18d79314df | ||
|
|
6f9c907db8 | ||
|
|
b20183d13e | ||
|
|
cdbc05a2b2 | ||
|
|
b218c1853b | ||
|
|
a2b9334422 | ||
|
|
c17553af3f | ||
|
|
b08c484bca | ||
|
|
e5f0833d51 | ||
|
|
6979f995d9 | ||
|
|
a0c3665725 | ||
|
|
b88122e7ca | ||
|
|
100490bf8d | ||
|
|
7130058741 | ||
|
|
7394f997db | ||
|
|
f7399cee8e | ||
|
|
5dd94cf83d | ||
|
|
78ba7b8f0d | ||
|
|
2dd1883f95 | ||
|
|
410c04ead8 | ||
|
|
a31fba5505 | ||
|
|
98587dfdf8 | ||
|
|
822518f920 | ||
|
|
442b265940 | ||
|
|
09bfd07da7 | ||
|
|
74a53ff545 | ||
|
|
6ae6aef389 | ||
|
|
4a44416156 | ||
|
|
a30b4f4290 | ||
|
|
f31791b23a | ||
|
|
4a9fc9cc87 | ||
|
|
3e6c52366b | ||
|
|
a014de80fe | ||
|
|
e8bbd79b70 | ||
|
|
b75ce26416 | ||
|
|
c193b0753e | ||
|
|
cf725983de | ||
|
|
fc16c8dde2 | ||
|
|
257ca66afe | ||
|
|
fde2a3e5ee | ||
|
|
6906daebdc | ||
|
|
d80bbaa50a | ||
|
|
a1a77b86ab | ||
|
|
267c93104b | ||
|
|
d08f476b3c | ||
|
|
7e9ddadc0f | ||
|
|
0cdf072c22 | ||
|
|
9f033074fa | ||
|
|
6d9db5a761 | ||
|
|
6cd6849580 | ||
|
|
db1dcc1053 | ||
|
|
af15fb3b3d | ||
|
|
9e9acd1592 | ||
|
|
60975da4e2 | ||
|
|
c25cdd4eab | ||
|
|
01284d3af8 | ||
|
|
c0185c1482 | ||
|
|
93866b7c77 | ||
|
|
d9db605bed | ||
|
|
13d2c1914f | ||
|
|
61d10d6aaf | ||
|
|
3601a3fd1c | ||
|
|
2d6210a893 | ||
|
|
26e8da310b | ||
|
|
07b2d9fb15 | ||
|
|
6c06652cfd | ||
|
|
4ee62cd2ef | ||
|
|
68c67633f5 | ||
|
|
6f65f91b49 | ||
|
|
475a109281 | ||
|
|
91eb43227a | ||
|
|
8c2a10268f | ||
|
|
ec8ec11cfd | ||
|
|
61bb9ac11e | ||
|
|
bd7d138f04 | ||
|
|
38015b6be2 | ||
|
|
d42c5d3e1d | ||
|
|
162b355bc8 | ||
|
|
d383680521 | ||
|
|
95ed032dcd | ||
|
|
0c5544e4dc | ||
|
|
54844fe68d | ||
|
|
760561d74e | ||
|
|
354eb8576c | ||
|
|
a725f2b97e | ||
|
|
29e8d0bf50 | ||
|
|
422c0966a6 | ||
|
|
9b706d30bf | ||
|
|
ceda8c0d23 | ||
|
|
b561a67ad1 | ||
|
|
4e34e8dd20 | ||
|
|
905058ee13 | ||
|
|
d3e443b766 | ||
|
|
d860eae924 | ||
|
|
71a518e9a5 | ||
|
|
2bbd6610c8 | ||
|
|
5bcee23e34 |
@@ -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
@@ -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}}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:"
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
@@ -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}).
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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."; }
|
||||
};
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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 = ¤t_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;
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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*
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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>
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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,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];
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user