Compare commits
120
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4db549061 | ||
|
|
4debd96adc | ||
|
|
30a4a95b7e | ||
|
|
a38aa58c0e | ||
|
|
e126a20df7 | ||
|
|
52cf2ee418 | ||
|
|
83a1e7e74b | ||
|
|
6069b7cfc0 | ||
|
|
41cc6d78db | ||
|
|
8561a817ea | ||
|
|
cfaf643d0e | ||
|
|
c505c4ca5f | ||
|
|
318f0e488e | ||
|
|
b22c9b7c84 | ||
|
|
bd491d025e | ||
|
|
6140c72aa6 | ||
|
|
7fcdc3f71c | ||
|
|
22feb208c2 | ||
|
|
ab65bbad4b | ||
|
|
64c66949e7 | ||
|
|
2fe18079a3 | ||
|
|
e0a66c7bc6 | ||
|
|
e4e5088ed6 | ||
|
|
aea281dcad | ||
|
|
b5aba16147 | ||
|
|
4ba1678561 | ||
|
|
8417f8eb04 | ||
|
|
55029e388f | ||
|
|
89c033bda9 | ||
|
|
0b57ae6b03 | ||
|
|
6588caafa6 | ||
|
|
b11fb97626 | ||
|
|
7a885c68b6 | ||
|
|
32278d3f77 | ||
|
|
c8dd33f5a3 | ||
|
|
1a7670600c | ||
|
|
a6ff40b0b2 | ||
|
|
54cf8b209c | ||
|
|
2e941e612f | ||
|
|
051f2bfe2f | ||
|
|
f13463e6b6 | ||
|
|
cd2fa1650d | ||
|
|
c23da3df34 | ||
|
|
95c1408d27 | ||
|
|
e278f4c24a | ||
|
|
365f2c4b2b | ||
|
|
ac59af9bd1 | ||
|
|
9d5d6203b9 | ||
|
|
1a66a2b8dd | ||
|
|
3b97ecef47 | ||
|
|
ed5b5a2a0c | ||
|
|
37cbab5bad | ||
|
|
11127b72b5 | ||
|
|
d5d87f1e64 | ||
|
|
fa6f228b87 | ||
|
|
21f1a2f47e | ||
|
|
5be7c6bd4e | ||
|
|
9f8e92ce93 | ||
|
|
4bbaca7fe5 | ||
|
|
cf1b4ef3e6 | ||
|
|
c3e36affa8 | ||
|
|
e9a614ba53 | ||
|
|
d57a462462 | ||
|
|
ac114aded4 | ||
|
|
74fc27de12 | ||
|
|
826b6767c9 | ||
|
|
89d5db2b5c | ||
|
|
1dd33050da | ||
|
|
0879638dda | ||
|
|
8a7b9b96ba | ||
|
|
23ea0644f8 | ||
|
|
bd6d856b0e | ||
|
|
6424177e3a | ||
|
|
0b92d2b03b | ||
|
|
bf04610296 | ||
|
|
ff9560f401 | ||
|
|
e0d6a21438 | ||
|
|
da794de6fd | ||
|
|
a1e941c43b | ||
|
|
3bb41960fd | ||
|
|
95fa78d3fd | ||
|
|
eff3dede3a | ||
|
|
7b4c7cffd7 | ||
|
|
8281721bde | ||
|
|
2ece55aa97 | ||
|
|
88c471a315 | ||
|
|
11afddc8da | ||
|
|
f7cac87979 | ||
|
|
5401e8417b | ||
|
|
c61a85e217 | ||
|
|
08cda36387 | ||
|
|
caa8a2d252 | ||
|
|
21eac9d921 | ||
|
|
d75384da6d | ||
|
|
008907161d | ||
|
|
102430c835 | ||
|
|
ce0e6e1d4f | ||
|
|
8c6ffdd911 | ||
|
|
a5a8f9d745 | ||
|
|
1c715483b4 | ||
|
|
08706b7cba | ||
|
|
c1045f2c28 | ||
|
|
46d451ce74 | ||
|
|
1c57fc61d8 | ||
|
|
e56851056d | ||
|
|
28399fefc8 | ||
|
|
7f2e83794e | ||
|
|
1f73b075c9 | ||
|
|
b4026fd169 | ||
|
|
efeb577933 | ||
|
|
fdd8ff04a3 | ||
|
|
89cc2374c7 | ||
|
|
5fc4ee50f6 | ||
|
|
d8a9993f63 | ||
|
|
96fe1eff44 | ||
|
|
033dae3772 | ||
|
|
5efe15a79e | ||
|
|
3d00dbcd55 | ||
|
|
10b72648a8 | ||
|
|
e5dd190874 |
@@ -6,3 +6,40 @@ bdb473cbdb119f3d9060d48f75f965cbd45f6d7a
|
||||
|
||||
# More clang-format: liboslquery, oslinfo, oslc, osl.imageio, osltoy (#1220)
|
||||
bf366d7a90c46599b82071dac6dbef7c5e3ca157
|
||||
|
||||
# Turn on clang-format for cpp files in testsuite (#1269)
|
||||
00c895fc642eb89685797c292048bdff15d675e7
|
||||
5e848fb761261521a3ee7cd8a4f6814f32fe4a47
|
||||
|
||||
# CI: Change our clang-format standard to clang11 (#1372)
|
||||
91d22ebe2f65d4ed0599e421172a15d99fe0e1b4
|
||||
|
||||
# More clang-format (this time, testrender and liboslnoise) (#1511)
|
||||
08706b7cbac781b6a9389780428016be985d9d89
|
||||
|
||||
# clang-format #1509
|
||||
b4026fd1695c08532557b3ba1c2142323087ccf9
|
||||
1f73b075c99861afa42fac44567b37f797bc72f2
|
||||
7f2e83794e6fa63d5180653cffb77be2cc38b32b
|
||||
28399fefc890442b5ac020e7a90cee0d5bf9f03c
|
||||
e56851056d33233b0bb8324faac251907099961a
|
||||
1c57fc61d8ab7c3f309be4335e4c71c26399edd4
|
||||
46d451ce74d00e904874df476ebeca19bb119ea9
|
||||
c1045f2c2845a98e661c7181932a031eb3c76063
|
||||
|
||||
# More clang-format (#1512)
|
||||
8c6ffdd911b9eb7db4adf41ab88891360452d7c5
|
||||
|
||||
# style: more clang-format (#1515)
|
||||
102430c83554fe7e328cd8c3317db00507bcfaba
|
||||
|
||||
# Revert some formatting (#1518)
|
||||
21eac9d9215d071b0a7b9ce2c32f189ed0c62c4a
|
||||
|
||||
# Another round of clang-format (#1540)
|
||||
38015b6be28643254aea530154b7860136cf5e15
|
||||
89d5db2b5c5fda79184d8245d903e580fc6a4e9c
|
||||
|
||||
# clang-format: the very last piece of the puzzle (#1555)
|
||||
4ee62cd2ef05543f818f4d95a19efc1d684a7381
|
||||
5be7c6bd4e7bd2e560cb6be8c06f11985384a87a
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
# Copyright 2008-present Contributors to the Open Shading Language project.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
|
||||
name: Analysis
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run nightly while we're still working our way through the warnings
|
||||
- cron: "0 8 * * *"
|
||||
# Run unconditionally once weekly
|
||||
# - cron: "0 0 * * 0"
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- '*analysis*'
|
||||
# Allow manual kicking off of the workflow from github.com
|
||||
workflow_dispatch:
|
||||
|
||||
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:
|
||||
|
||||
aswf:
|
||||
name: "SonarCloud Analysis"
|
||||
if: |
|
||||
github.repository == 'AcademySoftwareFoundation/OpenShadingLanguage'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
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
|
||||
vfxyear: 2022
|
||||
vfxsuffix: -clang13
|
||||
cxx_std: 14
|
||||
openimageio_ver: master
|
||||
python_ver: 3.9
|
||||
pybind11_ver: v2.9.0
|
||||
simd: avx2,f16c
|
||||
batched: b8_AVX2,b16_AVX512
|
||||
coverage: 1
|
||||
# skip_tests: 1
|
||||
sonar: 1
|
||||
setenvs: export SONAR_SCANNER_VERSION=4.7.0.2747
|
||||
SONAR_SERVER_URL="https://sonarcloud.io"
|
||||
BUILD_WRAPPER_OUT_DIR=bw_output
|
||||
OSL_CMAKE_BUILD_WRAPPER="build-wrapper-linux-x86-64 --out-dir bw_output"
|
||||
CMAKE_BUILD_TYPE=Debug
|
||||
CMAKE_UNITY_BUILD=OFF
|
||||
CODECOV=1
|
||||
TESTRENDER_AA=1
|
||||
OSL_TESTSUITE_SKIP_DIFF=1
|
||||
CTEST_TEST_TIMEOUT=1200
|
||||
OSL_CMAKE_FLAGS="-DOSL_TEST_BIG_TIMEOUT=1200 -DUSE_QT=0"
|
||||
CTEST_EXCLUSIONS="broken|noise-reg.regress|noise-gabor-reg.regress"
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
container:
|
||||
image: aswf/ci-osl:${{matrix.vfxyear}}${{matrix.vfxsuffix}}
|
||||
env:
|
||||
CXX: ${{matrix.cxx_compiler}}
|
||||
CC: ${{matrix.cc_compiler}}
|
||||
CMAKE_CXX_STANDARD: ${{matrix.cxx_std}}
|
||||
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
|
||||
# positives, every time we download a dependency. We should use it only
|
||||
# on CI runs where we are producing artifacts that users might rely on.
|
||||
# - name: Harden Runner
|
||||
# uses: step-security/harden-runner@248ae51c2e8cc9622ecf50685c8bf7150c6e8813 # v1.4.3
|
||||
# with:
|
||||
# egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
- name: Prepare ccache timestamp
|
||||
id: ccache_cache_keys
|
||||
run: echo "::set-output name=date::`date -u +'%Y-%m-%dT%H:%M:%SZ'`"
|
||||
- name: ccache
|
||||
id: ccache
|
||||
uses: actions/cache@c3f1317a9e7b1ef106c153ac8c0f00fed3ddbc0d # v3.0.4
|
||||
with:
|
||||
path: /tmp/ccache
|
||||
key: ${{github.job}}-${{matrix.nametag}}-${{steps.ccache_cache_keys.outputs.date}}
|
||||
restore-keys: ${{github.job}}-
|
||||
- name: Build setup
|
||||
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}}
|
||||
src/build-scripts/gh-installdeps.bash
|
||||
- name: Build
|
||||
run: src/build-scripts/ci-build.bash
|
||||
- name: Testsuite
|
||||
if: matrix.skip_tests != '1'
|
||||
run: src/build-scripts/ci-test.bash
|
||||
- name: Code coverage
|
||||
if: matrix.coverage == '1'
|
||||
run: src/build-scripts/ci-coverage.bash
|
||||
- name: Sonar-scanner
|
||||
if: matrix.sonar == 1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
run: |
|
||||
sonar-scanner -X --define sonar.host.url="${{ env.SONAR_SERVER_URL }}" --define sonar.cfamily.build-wrapper-output="build/bw_output" --define sonar.cfamily.gcov.reportsPath="_coverage"
|
||||
+166
-84
@@ -23,6 +23,13 @@ on:
|
||||
# Full nightly build
|
||||
- cron: "0 6 * * *"
|
||||
|
||||
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:
|
||||
|
||||
@@ -38,10 +45,9 @@ jobs:
|
||||
vfxyear: 2019
|
||||
vfxsuffix: -clang9
|
||||
cxx_std: 14
|
||||
openimageio_ver: v2.2.17.0
|
||||
openimageio_ver: v2.3.17.0
|
||||
python_ver: 2.7
|
||||
pybind11_ver: v2.4.2
|
||||
setenvs: export xUSE_PYTHON=0
|
||||
- desc: clang9/C++14 llvm9 oiio-release boost1.66 avx2 exr2.3 py2.7
|
||||
nametag: linux-clang9-llvm9
|
||||
os: ubuntu-18.04
|
||||
@@ -71,7 +77,7 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
vfxyear: 2020
|
||||
cxx_std: 14
|
||||
openimageio_ver: v2.2.17.0
|
||||
openimageio_ver: v2.3.17.0
|
||||
python_ver: 3.7
|
||||
pybind11_ver: v2.5.0
|
||||
simd: sse4.2
|
||||
@@ -82,7 +88,7 @@ jobs:
|
||||
vfxyear: 2021
|
||||
vfxsuffix: -clang11
|
||||
cxx_std: 17
|
||||
openimageio_ver: dev-2.2
|
||||
openimageio_ver: dev-2.3
|
||||
python_ver: 3.7
|
||||
pybind11_ver: v2.7.0
|
||||
simd: avx2,f16c
|
||||
@@ -111,6 +117,7 @@ jobs:
|
||||
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
|
||||
nametag: linux-icc
|
||||
os: ubuntu-latest
|
||||
vfxyear: 2022
|
||||
vfxsuffix: -clang13
|
||||
@@ -126,7 +133,8 @@ 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 llvm13 py3.9 boost1.76 exr3.1 oiio2.3 avx2
|
||||
nametag: linux-icx
|
||||
os: ubuntu-latest
|
||||
vfxyear: 2022
|
||||
vfxsuffix: -clang13
|
||||
@@ -146,11 +154,71 @@ jobs:
|
||||
vfxyear: 2019
|
||||
vfxsuffix: -clang9
|
||||
cxx_std: 14
|
||||
openimageio_ver: v2.2.17.0
|
||||
openimageio_ver: v2.3.17.0
|
||||
python_ver: 2.7
|
||||
pybind11_ver: v2.6.2
|
||||
simd: 0
|
||||
setenvs: export USE_PYTHON=0 PUGIXML_VERSION=v1.8
|
||||
setenvs: export PUGIXML_VERSION=v1.8
|
||||
|
||||
# Address and leak sanitizers
|
||||
- desc: sanitizers
|
||||
nametag: sanitizer
|
||||
os: ubuntu-latest
|
||||
vfxyear: 2022
|
||||
vfxsuffix: -clang13
|
||||
cc_compiler: clang
|
||||
cxx_compiler: clang++
|
||||
cxx_std: 17
|
||||
openimageio_ver: master
|
||||
python_ver: 3.9
|
||||
pybind11_ver: v2.9.0
|
||||
simd: avx2,f16c
|
||||
batched: b8_AVX2
|
||||
setenvs: export OSL_CMAKE_FLAGS="-DSANITIZE=address -DOSL_TEST_BIG_TIMEOUT=1200"
|
||||
CMAKE_BUILD_TYPE=Debug
|
||||
CTEST_TEST_TIMEOUT=1200
|
||||
CTEST_EXCLUSIONS="broken|noise-reg.regress|noise-gabor-reg.regress|example-.*deformer|spline-reg.regress.batched|osl-imageio"
|
||||
OSL_OPTIONS=llvm_debugging_symbols=1
|
||||
TESTRENDER_AA=1
|
||||
OSL_TESTSUITE_SKIP_DIFF=1
|
||||
# Sanitizer notes:
|
||||
# - There are a handful of tests we disable entirely with
|
||||
# CTEST_EXCLUSIONS because they are irrelevant or just cannot be
|
||||
# made to be clean (and that's ok).
|
||||
# - Tests with sanitizers run slow, so we increase timeouts, and
|
||||
# also set AA to 1 for render tests to speed them up.
|
||||
# OSL_TESTSUITE_SKIP_DIFF prevents making the AA=1 image result
|
||||
# fail, but that's ok because every other CI test is checking
|
||||
# the results; here we have no reason to believe results will
|
||||
# differ from other tests, we just need to run with sanitizers
|
||||
# turned on.
|
||||
# - In testing.cmake, we rig texture tests to disable the leak
|
||||
# sanitizer, because we can't eliminate some completely benign
|
||||
# leaks from the texture system, and because they are called
|
||||
# from JITed code, we don't get a clean stack trace of things
|
||||
# that happen in OIIO and therefore we just can't enumerate the
|
||||
# allowed exceptions. So we trust that OIIO itself tests the
|
||||
# texture system adequately and is able to ignore the benign
|
||||
# "leaks."
|
||||
|
||||
# Test formatting. This test entry doesn't do a full build, it
|
||||
# just runs clang-format on everything, and passes if nothing is
|
||||
# misformatted. Upon failure, the build artifact will be the full
|
||||
# source code with the formatting fixed (diffs will also appear in
|
||||
# the console output).
|
||||
- desc: "clang-format"
|
||||
nametag: clang-format
|
||||
os: ubuntu-latest
|
||||
vfxyear: 2022
|
||||
vfxsuffix: -clang14
|
||||
cxx_std: 17
|
||||
openimageio_ver: release
|
||||
python_ver: 3.9
|
||||
simd: avx2,f16c
|
||||
batched: b8_AVX2
|
||||
skip_tests: 1
|
||||
setenvs: export BUILDTARGET=clang-format
|
||||
OPENIMAGEIO_CMAKE_FLAGS=-DUSE_PYTHON=0
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
container:
|
||||
@@ -167,13 +235,20 @@ jobs:
|
||||
USE_BATCHED: ${{matrix.batched}}
|
||||
USE_SIMD: ${{matrix.simd}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
# We would like to use harden-runner, but it flags too many false
|
||||
# positives, every time we download a dependency. We should use it only
|
||||
# on CI runs where we are producing artifacts that users might rely on.
|
||||
# - name: Harden Runner
|
||||
# uses: step-security/harden-runner@248ae51c2e8cc9622ecf50685c8bf7150c6e8813 # v1.4.3
|
||||
# with:
|
||||
# egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2
|
||||
- name: Prepare ccache timestamp
|
||||
id: ccache_cache_keys
|
||||
run: echo "::set-output name=date::`date -u +'%Y-%m-%dT%H:%M:%SZ'`"
|
||||
- name: ccache
|
||||
id: ccache
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@c3f1317a9e7b1ef106c153ac8c0f00fed3ddbc0d # v3.0.4
|
||||
with:
|
||||
path: /tmp/ccache
|
||||
key: ${{github.job}}-${{matrix.nametag}}-${{steps.ccache_cache_keys.outputs.date}}
|
||||
@@ -199,7 +274,7 @@ jobs:
|
||||
- name: Testsuite
|
||||
if: matrix.skip_tests != '1'
|
||||
run: src/build-scripts/ci-test.bash
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
|
||||
if: failure()
|
||||
with:
|
||||
name: osl-${{github.job}}-${{matrix.nametag}}
|
||||
@@ -243,11 +318,44 @@ jobs:
|
||||
setenvs: export LLVM_VERSION=10.0.0
|
||||
OPENIMAGEIO_CMAKE_FLAGS="-DBUILD_FMT_VERSION=7.0.1"
|
||||
PUGIXML_VERSION=v1.10
|
||||
- desc: latest releases gcc11/C++17 llvm13 boost1.71 exr3.1 py3.8 avx2 batch-b16avx512
|
||||
- desc: latest releases gcc11/C++17 llvm13 boost1.71 exr3.1 py3.9 avx2 batch-b16avx512
|
||||
nametag: linux-latest-releases
|
||||
os: ubuntu-20.04
|
||||
cxx_compiler: g++-11
|
||||
cxx_std: 17
|
||||
fmt_ver: 9.1.0
|
||||
openexr_ver: v3.1.5
|
||||
openimageio_ver: master
|
||||
pybind11_ver: v2.10.0
|
||||
python_ver: 3.9
|
||||
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
|
||||
- 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
|
||||
cxx_compiler: g++-12
|
||||
cxx_std: 17
|
||||
fmt_ver: master
|
||||
openexr_ver: main
|
||||
openimageio_ver: master
|
||||
pybind11_ver: master
|
||||
python_ver: "3.10"
|
||||
simd: avx2,f16c
|
||||
batched: b8_AVX2,b8_AVX512,b16_AVX512
|
||||
setenvs: export LLVM_VERSION=14.0.0
|
||||
LLVM_DISTRO_NAME=ubuntu-18.04
|
||||
OPENCOLORIO_VERSION=main
|
||||
PUGIXML_VERSION=master
|
||||
- desc: clang14/C++17 llvm14 boost1.71 exr3.1 py3.8 avx2 batch-b16avx512
|
||||
nametag: linux-latest-releases-clang
|
||||
os: ubuntu-20.04
|
||||
cxx_compiler: clang++
|
||||
cc_compiler: clang
|
||||
cxx_std: 17
|
||||
fmt_ver: 8.1.1
|
||||
openexr_ver: v3.1.5
|
||||
openimageio_ver: master
|
||||
@@ -255,26 +363,10 @@ jobs:
|
||||
python_ver: 3.8
|
||||
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.1
|
||||
PUGIXML_VERSION=v1.11.4
|
||||
- desc: bleeding edge gcc11/C++17 llvm14 oiio/ocio/exr/pybind-master boost1.71 py3.9 avx2 batch-b16avx512
|
||||
nametag: linux-bleeding-edge
|
||||
os: ubuntu-20.04
|
||||
cxx_compiler: g++-11
|
||||
cxx_std: 17
|
||||
fmt_ver: master
|
||||
openexr_ver: main
|
||||
openimageio_ver: master
|
||||
pybind11_ver: master
|
||||
python_ver: 3.9
|
||||
simd: avx2,f16c
|
||||
batched: b8_AVX2,b8_AVX512,b16_AVX512
|
||||
setenvs: export LLVM_VERSION=14.0.0
|
||||
LLVM_DISTRO_NAME=ubuntu-18.04
|
||||
OPENCOLORIO_VERSION=main
|
||||
PUGIXML_VERSION=master
|
||||
OPENCOLORIO_VERSION=v2.1.2
|
||||
PUGIXML_VERSION=v1.11.4
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
env:
|
||||
@@ -289,13 +381,20 @@ jobs:
|
||||
USE_BATCHED: ${{matrix.batched}}
|
||||
USE_SIMD: ${{matrix.simd}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
# We would like to use harden-runner, but it flags too many false
|
||||
# positives, every time we download a dependency. We should use it only
|
||||
# on CI runs where we are producing artifacts that users might rely on.
|
||||
# - name: Harden Runner
|
||||
# uses: step-security/harden-runner@248ae51c2e8cc9622ecf50685c8bf7150c6e8813 # v1.4.3
|
||||
# with:
|
||||
# egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2
|
||||
- name: Prepare ccache timestamp
|
||||
id: ccache_cache_keys
|
||||
run: echo "::set-output name=date::`date -u +'%Y-%m-%dT%H:%M:%SZ'`"
|
||||
- name: ccache
|
||||
id: ccache
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@c3f1317a9e7b1ef106c153ac8c0f00fed3ddbc0d # v3.0.4
|
||||
with:
|
||||
path: /tmp/ccache
|
||||
key: ${{github.job}}-${{matrix.nametag}}-${{steps.ccache_cache_keys.outputs.date}}
|
||||
@@ -313,7 +412,7 @@ jobs:
|
||||
- name: Testsuite
|
||||
if: matrix.skip_tests != '1'
|
||||
run: src/build-scripts/ci-test.bash
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
|
||||
if: failure()
|
||||
with:
|
||||
name: osl-${{github.job}}-${{matrix.nametag}}
|
||||
@@ -326,88 +425,71 @@ jobs:
|
||||
macos:
|
||||
name: "${{matrix.os}} appleclang${{matrix.aclang}}/C++${{matrix.cxx_std}} py${{matrix.python_ver}} ${{matrix.desc}}"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- desc: llvm11
|
||||
os: macos-10.15
|
||||
nametag: macos10-py39
|
||||
cxx_std: 14
|
||||
python_ver: 3.9
|
||||
aclang: 12
|
||||
- desc: llvm11
|
||||
- desc: MacOS-11
|
||||
os: macos-11
|
||||
nametag: macos11-py39
|
||||
cc_compiler: /usr/local/opt/llvm@14/bin/clang
|
||||
cxx_compiler: /usr/local/opt/llvm@14/bin/clang++
|
||||
cxx_std: 17
|
||||
python_ver: 3.9
|
||||
python_ver: "3.10"
|
||||
aclang: 13
|
||||
setenvs: export LLVMBREWVER="@14" DO_BREW_UPDATE=1
|
||||
- desc: MacOS-12
|
||||
os: macos-12
|
||||
nametag: macos11-p310
|
||||
cc_compiler: /usr/local/opt/llvm@15/bin/clang
|
||||
cxx_compiler: /usr/local/opt/llvm@15/bin/clang++
|
||||
cxx_std: 17
|
||||
python_ver: "3.10"
|
||||
aclang: 13
|
||||
setenvs: export LLVMBREWVER="@15" DO_BREW_UPDATE=1
|
||||
runs-on: ${{matrix.os}}
|
||||
env:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
CXX: ${{matrix.cxx_compiler}}
|
||||
CC: ${{matrix.cc_compiler}}
|
||||
CMAKE_CXX_STANDARD: ${{matrix.cxx_std}}
|
||||
PYTHON_VERSION: ${{matrix.python_ver}}
|
||||
OPENIMAGEIO_VERSION: ${{matrix.openimageio_ver}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2
|
||||
- name: Prepare ccache timestamp
|
||||
id: ccache_cache_keys
|
||||
run: echo "::set-output name=date::`date -u +'%Y-%m-%dT%H:%M:%SZ'`"
|
||||
- name: ccache
|
||||
id: ccache
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@c3f1317a9e7b1ef106c153ac8c0f00fed3ddbc0d # v3.0.4
|
||||
with:
|
||||
path: /Users/runner/.ccache
|
||||
key: ${{github.job}}-${{matrix.os}}-${{steps.ccache_cache_keys.outputs.date}}
|
||||
restore-keys: ${{github.job}}-${{matrix.os}}-
|
||||
key: ${{github.job}}-${{matrix.nametag}}-${{steps.ccache_cache_keys.outputs.date}}
|
||||
restore-keys: ${{github.job}}-${{matrix.nametag}}-
|
||||
- name: Build setup
|
||||
run: src/build-scripts/ci-startup.bash
|
||||
run: |
|
||||
${{matrix.setenvs}}
|
||||
src/build-scripts/ci-startup.bash
|
||||
- name: Dependencies
|
||||
run: |
|
||||
source src/build-scripts/install_homebrew_deps.bash
|
||||
# OPENIMAGEIO_CMAKE_FLAGS="-DOIIO_BUILD_TESTS=0 -DUSE_OPENGL=0"
|
||||
# source src/build-scripts/build_openimageio.bash
|
||||
brew install --display-times -q openimageio
|
||||
PYTHONPATH=$PYTHONPATH:/usr/local/python${PYTHON_VERSION}/site-packages
|
||||
if [[ "$OPENIMAGEIO_VERSION" != "" ]] ; then \
|
||||
OPENIMAGEIO_CMAKE_FLAGS="-DOIIO_BUILD_TESTS=0 -DUSE_OPENGL=0" ; \
|
||||
source src/build-scripts/build_openimageio.bash ; \
|
||||
else \
|
||||
brew install --display-times -q openimageio ; \
|
||||
PYTHONPATH=$PYTHONPATH:/usr/local/python${PYTHON_VERSION}/site-packages ; \
|
||||
fi
|
||||
src/build-scripts/save-env.bash
|
||||
- name: Build
|
||||
run: |
|
||||
src/build-scripts/ci-build.bash
|
||||
- name: Testsuite
|
||||
run: src/build-scripts/ci-test.bash
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
|
||||
if: failure()
|
||||
with:
|
||||
name: osl-${{github.job}}
|
||||
name: osl-${{github.job}}-${{matrix.nametag}}
|
||||
path: |
|
||||
build/*.cmake
|
||||
build/CMake*
|
||||
build/testsuite/*/*.*
|
||||
|
||||
|
||||
clang-format:
|
||||
# Test formatting. This test entry doesn't do a full build, it just runs
|
||||
# clang-format on everything, and passes if nothing is misformatted.
|
||||
# Upon failure, the build artifact will be the full source code with the
|
||||
# formatting fixed (diffs will also appear in the console output).
|
||||
name: "clang-format verification"
|
||||
runs-on: ubuntu-18.04
|
||||
container:
|
||||
image: aswf/ci-osl:2021-clang11
|
||||
env:
|
||||
BUILDTARGET: run-clang-format
|
||||
CMAKE_CXX_STANDARD: 17
|
||||
PYTHON_VERSION: 3.7
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build setup
|
||||
run: |
|
||||
src/build-scripts/ci-startup.bash
|
||||
- name: Dependencies
|
||||
run: |
|
||||
src/build-scripts/gh-installdeps.bash
|
||||
- name: Build
|
||||
run: |
|
||||
src/build-scripts/ci-build.bash
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: osl-${{github.job}}
|
||||
path: src/*/*.{cpp,h}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
name: Scorecards supply-chain security
|
||||
on:
|
||||
# Only the default branch is supported.
|
||||
branch_protection_rule:
|
||||
schedule:
|
||||
- cron: '44 20 * * 6'
|
||||
push:
|
||||
branches: [ "main", "scorecard" ]
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecards analysis
|
||||
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"
|
||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # v3.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@3e15ea8318eee9b333819ec77a36aca8d39df13e # v1.1.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# (Optional) Read-only PAT token. Uncomment the `repo_token` line below if:
|
||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||
# - you are installing Scorecards on a *private* repository
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
|
||||
# repo_token: ${{ secrets.SCORECARD_READ_TOKEN }}
|
||||
|
||||
# Publish the results for public repositories to enable scorecard badges. For more details, see
|
||||
# https://github.com/ossf/scorecard-action#publishing-results.
|
||||
# For private repositories, `publish_results` will automatically be set to `false`, regardless
|
||||
# of the value entered here.
|
||||
publish_results: true
|
||||
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@5f532563584d71fdef14ee64d17bafb34f751ce5 # v1.0.26
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
@@ -9,4 +9,5 @@ build
|
||||
*.pyc
|
||||
*.log
|
||||
.vscode
|
||||
.envrc
|
||||
|
||||
|
||||
@@ -50,4 +50,4 @@ This is a checklist for TSC's to review as part of the intake process. The TSC s
|
||||
- [X] License scan completed and no issues found
|
||||
- Minor issues were found but already fixed in PR https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/pull/1145
|
||||
- [X] Code repository imported to ASWF GitHub organization
|
||||
- [ ] Developer Certificate of Origin past commit signoff done and DCO Probot enabled.
|
||||
- [X] Developer Certificate of Origin post commit signoff done and DCO Probot enabled.
|
||||
|
||||
+132
-9
@@ -1,8 +1,84 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
<!-- Copyright Contributors to the Open Shading Language Project. -->
|
||||
|
||||
Release 1.12 -- ?? (compared to 1.11)
|
||||
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)
|
||||
|
||||
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:
|
||||
|
||||
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)
|
||||
|
||||
SIMD batched shading mode:
|
||||
* Fix some array overruns (asymptomatic, but still potentially buggy) in
|
||||
common_ancestor_between. #1577 (1.13.0.2)
|
||||
|
||||
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)
|
||||
|
||||
Performance improvements:
|
||||
|
||||
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 -- 1 Oct 2022 (compared to 1.11)
|
||||
----------------------------------------------
|
||||
Big Deal Changes:
|
||||
* **Batch shading**: A fully operational "batch shading" support when using
|
||||
CPUs supporting the Intel AVX2 or AVX512 instruction set architectures,
|
||||
allows shading 8 or 16 points at a time, accelerated by using SIMD
|
||||
instructions. (Changes contributed by Intel.)
|
||||
* **OptiX**: A reasonable subset of the OSL language can run on NVIDIA GPUs
|
||||
for Cuda or OptiX-based renderers.
|
||||
* **Standardized material closures**: Synchronize with MaterialX on a minimum
|
||||
standard set of material closures. This is reflected in both the OSL spec as
|
||||
well as reference implementations of those closures in testrender. #1533
|
||||
#1536 #1537 #1538 #1539 #1541 #1542 #1547 #1557
|
||||
|
||||
Dependency and standards requirements changes:
|
||||
* The minimum (and default) compilation mode is now C++14. C++17 and 20 are
|
||||
also supported. #1362 #1369 (1.12.2)
|
||||
@@ -33,6 +109,8 @@ OSL Standard library:
|
||||
* Fix previously-broken color conversions from RGB to xyY. #1410 (1.12.3)
|
||||
* Fully removed MaterialX shaders (get those from the MaterialX project).
|
||||
#1450 (1.12.3)
|
||||
* Fix incorrect implementation of `matrix4 * vector4` in vector4.h #1513
|
||||
(1.12.5.0)
|
||||
|
||||
API changes, new options, new ShadingSystem features (for renderer writers):
|
||||
* Custom experimental llvm optimization levels 10, 11, 12, and 13. These
|
||||
@@ -51,8 +129,14 @@ API changes, new options, new ShadingSystem features (for renderer writers):
|
||||
RendererServices::get_userdata(). #1391 (1.12.3)
|
||||
* Better hiding of the Matrix22 class, which was never actually part of the
|
||||
public APIs. #1480 (1.12.4.5)
|
||||
* Add ACES2065-1 and ACEScg as shading system color spaces (#1486) (1.12.4.6)
|
||||
* Expanded warnings (via enabling the "opt_warnings" attribute of the
|
||||
ShadingSystem) for operations that try to create new strings mid-shader, or
|
||||
that need to access the characters of strings mid-shader. These are only
|
||||
triggered for those cases that cannot be resolved by the end of the "runtime
|
||||
optimization" phase. #1497 (1.12.4.6)
|
||||
|
||||
Continued work on experimental SIMD batched shading mode:
|
||||
SIMD batched shading mode:
|
||||
* Added support for masked operations to LLVMUtil. #1248 #1250 (1.12.0.0)
|
||||
* Add interface to ShadingSystem for batched execution. #1272 (1.12.0.1)
|
||||
* Add interface to batched RendererServices. #1276 (1.12.0.1)
|
||||
@@ -65,7 +149,7 @@ Continued work on experimental SIMD batched shading mode:
|
||||
* ISA-specific modules. #1345 (1.12.2)
|
||||
* Introduction of CI testing of batched mode. #1357 #1367 (1.12.2)
|
||||
* Control flow and string ops. #1372 (1.12.2)
|
||||
* Matrix operations. #1378 (1.12.2)
|
||||
* Matrix operations. #1378 (1.12.2) #1485 (1.12.4.6)
|
||||
* Batched algebraic, trig, and transcendental functions. #1385 (1.12.2)
|
||||
* Batched noise. #1394 (1.12.3)
|
||||
* Batched implementation of all color operations. #1408 (1.12.3)
|
||||
@@ -77,8 +161,9 @@ Continued work on experimental 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)
|
||||
|
||||
Continued work on experimental OptiX rendering:
|
||||
OptiX rendering:
|
||||
* Explicitly set the OptiX pipeline stack size. #1254 (1.12.0.0)
|
||||
* CI tests now at least compile and build with USE_OPTIX=1 (though not yet
|
||||
run the tests). #1281 (1.12.0.1)
|
||||
@@ -95,10 +180,12 @@ Continued work on experimental OptiX rendering:
|
||||
* Fix race conditions when compiling for OptiX 7. #1411 (1.12.3)
|
||||
* osl_get_attribute() uses device strings when compiling for OptiX.
|
||||
#1435 (1.12.3)
|
||||
* Fix issue with OptiX + clang 14 with duplicate symbols. #1561 (1.12.6.0)
|
||||
|
||||
Performance improvements:
|
||||
* Less mutex locking around use and retrieval of ColorSystem related to
|
||||
doing color transforms. #1405 (1.12.3)
|
||||
* Constant folding of `startswith()`. #1507 (1.12.5.0)
|
||||
|
||||
Bug fixes and other improvements (internals):
|
||||
* Fix derivatives of texture calls when only derivatives of the "alpha"
|
||||
@@ -135,6 +222,15 @@ Bug fixes and other improvements (internals):
|
||||
globals. #1462 (1.12.4.4)
|
||||
* Print all 4 levels of version numbers in help messages. #1477 (1.12.4.4)
|
||||
* Fix GPU code generation crash. #1479 (1.12.4.4)
|
||||
* Work to transition internals to use modern std::format notation for
|
||||
formatted output. #1487 #1490 (1.12.4.6) #1504 #1506 (1.12.5.0)
|
||||
* testrender improvements:
|
||||
* Fix testrender memory error on teardown. #1499 (1.12.4.6)
|
||||
* Modernize the sampler in testrender, improving quality and performance.
|
||||
#1534 (1.12.6.0)
|
||||
* 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)
|
||||
|
||||
Internals/developer concerns:
|
||||
* Use the `final` keyword in certain internal classes where applicable.
|
||||
@@ -152,6 +248,18 @@ Internals/developer concerns:
|
||||
whenever we need to parse strings. #1432 (1.12.3)
|
||||
* Avoid use of OIIO::string_view::str() which is not corresponding to the
|
||||
official C++17 std::string_view. #1467 (1.12.4.4)
|
||||
* Prototype of "free function" approach that will someday mostly supplant
|
||||
the way we use RendererServices, and will help to unlock feature completion
|
||||
for GPU and other back ends. This experimental feature is not expected
|
||||
to be used in OSL 1.12. #1494 (1.12.5.0)
|
||||
* Work on gradually converting printf-style formatted strings to fmt /
|
||||
std::format style. #1493 (1.12.5.0)
|
||||
* LLVM_Util: allow naming of llvm symbols to help with IR debugging. #1530
|
||||
(1.12.6.0)
|
||||
* clang-format the code base. #1508 #1509 #1511 #1512 #1515 #1518 #1540
|
||||
(1.12.5.0) #1555 #1562 #1568 (1.12.6.0)
|
||||
* A round of spell-checking all the comments in the code base. #1550
|
||||
(1.12.5.0)
|
||||
|
||||
Build & test system improvements:
|
||||
* CMake build system and scripts:
|
||||
@@ -193,17 +301,19 @@ Build & test system improvements:
|
||||
(1.12.4.4)
|
||||
* 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)
|
||||
- PugiXML build fixes on some systems. #1262 (1.12.0.1/1.11.8)
|
||||
- Cuda/OptiX back end: Add `__CUDADEVRT_INTERNAL__` define to bitcode
|
||||
generation, needed to avoid duplicate cudaMalloc symbols with CUDA9+
|
||||
#1271 (1.12.0.1)
|
||||
- Build against LLVM 11 #1274 (1.12.0.1), LLVM 12 #1351 (1.12.1.0)
|
||||
#1412 (1.12.3), LLVM 13 #1420 (1.12.3)
|
||||
#1412 (1.12.3), LLVM 13 #1420 (1.12.3), LLVM 14 #1492 (1.12.4.6)
|
||||
LLVM 15 #1592 (1.12.6.2)
|
||||
- Fix build break against recent OIIO master change where m_mutex field
|
||||
was removed from ImageInput. #1281 (1.12.0.1/1.11.9)
|
||||
- Work to ensure that OIIO will build correctly against the upcoming
|
||||
Imath 3.0 and OpenEXR 3.0. #1299 (1.11.10/1.12.1) #1332 (1.11.11/1.12.1)
|
||||
#1341 (1.11.12/1.12.1) #1356 #1368 (1.11.13/1.12.2)
|
||||
#1341 (1.11.12/1.12.1) #1356 #1368 (1.11.13/1.12.2) #1489 (1.12.4.6)
|
||||
- Improved finding of llvm components when using static libraries. #1375
|
||||
(1.12.2)
|
||||
- No longer use boost regex, completely rely on std::regex now that OSL
|
||||
@@ -217,6 +327,8 @@ Build & test system improvements:
|
||||
compilers. #1459 #1473 #1475. (1.12.4.4)
|
||||
- Fixes for recent OIIO TextureSystem changes that hide Imath types.
|
||||
#1476 (1.12.4.4)
|
||||
- Changes to work correctly with OpenImageIO 2.4 and its master being
|
||||
the start of 2.5. #1569 (1.12.6.0)
|
||||
* Testing and Continuous integration (CI) systems:
|
||||
- Eliminate the old Travis CI and Appveyor. #1334 #1338 (1.12.1)
|
||||
- Use ccache + GitHub 'cache' action to greatly speed up CI runs. #1335
|
||||
@@ -225,14 +337,15 @@ Build & test system improvements:
|
||||
scripts for CentOS and Ubuntu ito a single script. #1338 (1.12.1)
|
||||
- CI tests clang11, also batched shading with clang. #1379 (1.12.2)
|
||||
- CI speeds up OIIO builds by not building its tests. #1380 (1.12.2)
|
||||
- CI tests gcc11. #1381 (1.12.2)
|
||||
- CI tests gcc11 #1381 (1.12.2) and gcc12 #1565 (1.12.6)
|
||||
- Deal with OpenColorIO changing its master branch to "main". #1429
|
||||
(1.12.3)
|
||||
- Fix tests for texture3d now that OIIO has dropped support for Field3D.
|
||||
#1437 (1.12.3)
|
||||
- Test against LLVM13/clang13 for the VFX Platform 2022 tests. #1434
|
||||
(1.12.3)
|
||||
- Test against MacOS-11. #1434 (1.12.3)
|
||||
- CI test against MacOS-11 #1434 (1.12.3) and MacOS-12 #1554 (1.12.6)
|
||||
#1522 (1.12.5)
|
||||
- Add testsuite coverage of environment(). #1438 (1.12.3)
|
||||
- Use a project-specific environment variable `OSL_CI` instead of the more
|
||||
generic `CI` to avoid clashes with other systems. #1446 (1.12.3)
|
||||
@@ -244,11 +357,18 @@ Build & test system improvements:
|
||||
#1472 (1.12.4.4)
|
||||
- Allow `-Werror` to be disabled even on CI branches. #1471 (1.12.4.4)
|
||||
- CI Tests against the Intel icc and icx compilers! #1459 #1473 (1.12.4.4)
|
||||
#1501 (1.12.5.0)
|
||||
- Overhaul of GHA ci.yml to use strategy matrix. #1474 (1.12.4.4)
|
||||
- Test against clang 14 and fix new warnings. #1498 (1.12.5.0)
|
||||
- Test against clang 15 and fix new warnings. #1586 (1.12.6.2)
|
||||
- A scorecards workflow guards against a variety of security issues of
|
||||
the CI system itself. #1529 (1.12.6.0)
|
||||
- Enable SonarCloud static analysis. #1551 #1556 #1563 (1.12.6.0)
|
||||
* Platform support:
|
||||
- Various Windows compile fixes. #1263 #1285 (1.12.0.1)
|
||||
- Windows+Cuda build fixes. #1292 (1.12.0.1)
|
||||
- Fix warnings about pointer casts on Windows. #1484 (1.12.4.5)
|
||||
- Various Windows build fixes. #1502 (1.12.5.0)
|
||||
* The oso and osl lexers/parsers are now given internal symbol names that
|
||||
are fully versioned, to avoid possible clash if multiple OSL releases are
|
||||
both linked into the same application. #1255 (1.12.0.0)
|
||||
@@ -263,6 +383,9 @@ Documentation:
|
||||
#1326 (1.12.1)
|
||||
* Fix missing explanation of the optional "errormessage" parameter to
|
||||
environment() and texture3d(). #1442 (1.12.3/1.11.17)
|
||||
* A SECURITY.md file explains how to confidentially report vulnerabilities.
|
||||
#1529 (1.12.6)
|
||||
* Document all the new MaterialX closures. #1564
|
||||
|
||||
|
||||
|
||||
@@ -730,7 +853,7 @@ Build & test system improvements:
|
||||
use clang library components for preprocessing. #1089 (1.11.3)
|
||||
* Add an optional build-time `EXTRA_WARNINGS` option (default: OFF) that
|
||||
enables even more picky than usual warnings. Fix many warnings that cropped
|
||||
up during testing, mostly related to unused function paramters. #1106 (1.11.3)
|
||||
up during testing, mostly related to unused function parameters. #1106 (1.11.3)
|
||||
* The testsuite can run in parallel, with a number of threads set by the
|
||||
environment variable `CTEST_PARALLEL_LEVEL`. #1119 (1.11.4)
|
||||
* oslconfig.h is now generated by a cmake configure_file step, from
|
||||
|
||||
+4
-1
@@ -3,7 +3,9 @@
|
||||
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
|
||||
cmake_minimum_required (VERSION 3.12)
|
||||
project (OSL VERSION 1.12.4.5
|
||||
|
||||
set (OSL_VERSION "1.13.1.0" CACHE STRING "Version")
|
||||
project (OSL VERSION ${OSL_VERSION}
|
||||
LANGUAGES CXX C
|
||||
HOMEPAGE_URL "https://github.com/AcademySoftwareFoundation/OpenShadingLanguage")
|
||||
set (PROJ_NAME ${PROJECT_NAME}) # short name
|
||||
@@ -161,6 +163,7 @@ include (pythonutils)
|
||||
include (externalpackages)
|
||||
include (flexbison)
|
||||
include (cuda_macros)
|
||||
include (llvm_macros)
|
||||
|
||||
# Include all our testing apparatus and utils, but not if it's a subproject
|
||||
if (${PROJECT_NAME}_BUILD_TESTS AND PROJECT_IS_TOP_LEVEL)
|
||||
|
||||
+13
-9
@@ -173,9 +173,16 @@ it really only applies to the particular file in which it appears.
|
||||
|
||||
#### Formatting
|
||||
|
||||
NEVER alter somebody else's code to reformat just because you found
|
||||
something that violates the rules. Let the group/author/leader know, and
|
||||
resist the temptation to change it yourself.
|
||||
We use clang-format to enforce formatting rules for the vast majority of the
|
||||
code base. It is automatically run during CI and is a CI failure if the code
|
||||
does not conform. There are, however, parts of the code base that are not
|
||||
clang-formatted, either because we have not yet put them under the
|
||||
clang-format regime, or because individual modules were deemed to be less
|
||||
clear with clang-format than with hand formatting.
|
||||
|
||||
For non-clang-format regions of code, NEVER alter somebody else's code to
|
||||
reformat just because you found something that violates the rules. Let the
|
||||
group/author/leader know, and resist the temptation to change it yourself.
|
||||
|
||||
Each line of text in your code should be at most 80 characters long.
|
||||
Exceptions are allowed for those rare cases where letting a line be longer
|
||||
@@ -217,13 +224,10 @@ Function calls should have a space between the function name and the opening
|
||||
parenthesis, NO space inside the parenthesis, except for a single blank
|
||||
space between each argument. For example:
|
||||
|
||||
x = foo (a, b); // Yes, this is always ok
|
||||
x = foo(a, b); // Yes
|
||||
|
||||
x = foo ( a, b ); // No
|
||||
x = foo (a,b); // No
|
||||
x = foo(a, b); // No
|
||||
x = foo(a); // Occasionally, this just looks better, when the function name is short,
|
||||
// and there's just one very short argument. What can I say, I do it too.
|
||||
|
||||
Function declarations: function names should begin at column 0 for a full
|
||||
function definition. (It's ok to violate this rule for very short inline
|
||||
@@ -233,7 +237,7 @@ functions within class definitions.)
|
||||
Here is a short code fragment that shows some of these rules in action:
|
||||
|
||||
static int
|
||||
function (int a, int b)
|
||||
function(int a, int b)
|
||||
{
|
||||
int x = a + b;
|
||||
if (a == 0 || b == 0) {
|
||||
@@ -244,7 +248,7 @@ Here is a short code fragment that shows some of these rules in action:
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
x += a * i;
|
||||
x *= foo (i); // function call
|
||||
x *= foo(i); // function call
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
+22
-23
@@ -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.22)
|
||||
* Build system: [CMake](https://cmake.org/) 3.12 or newer (tested through 3.24)
|
||||
|
||||
* 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 11.2)
|
||||
- Clang 3.4 or newer (tested through clang 13)
|
||||
- Microsoft Visual Studio **2017 or newer**
|
||||
- Intel C++ compiler icc **version 17 or newer** and 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 15)
|
||||
- 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.2 or newer** (tested through 2.3)
|
||||
* **[OpenImageIO](http://openimageio.org) 2.3 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,10 +40,14 @@ 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, or 14**, including clang
|
||||
libraries.
|
||||
* [LLVM](http://www.llvm.org) 9, 10, 11, 12, 13, 14, or 15, including
|
||||
clang libraries.
|
||||
|
||||
* [Boost](https://www.boost.org) 1.55 or newer (tested through boost 1.78)
|
||||
* (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.
|
||||
|
||||
* [Boost](https://www.boost.org) 1.55 or newer (tested through boost 1.80)
|
||||
* [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
|
||||
@@ -57,8 +61,8 @@ NEW or CHANGED dependencies since the last major release are **bold**.
|
||||
be operative.
|
||||
* (optional) Python: If you are building the Python bindings or running the
|
||||
testsuite:
|
||||
* Python >= 2.7 (tested against 2.7, 3.7, 3.8, 3.9)
|
||||
* pybind11 >= 2.4.2 (Tested through 2.9)
|
||||
* 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.
|
||||
@@ -93,19 +97,14 @@ Here are the steps to check out, build, and test the OSL distribution:
|
||||
full errors, not warnings.
|
||||
|
||||
4. After compilation, you'll end up with a full OSL distribution in
|
||||
dist/ARCH, where ARCH is the architecture you are building on, one of
|
||||
"linux", "linux64", "macosx", "windows", or "windows64".
|
||||
dist/
|
||||
|
||||
Note: The default is to make an optimized "release" build. If
|
||||
instead type 'make debug' at the top level, you will end up with
|
||||
a debug build (no optimization, full symbols) in "dist/ARCH.debug".
|
||||
|
||||
5. Add the "dist/ARCH/bin" to your $PATH, and "dist/ARCH/lib" to your
|
||||
$LD_LIBRAY_PATH (or $DYLD_LIBRARY_PATH on OS X), or copy the contents
|
||||
5. Add the "dist/bin" to your $PATH, and "dist/lib" to your
|
||||
$LD_LIBRAY_PATH (or $DYLD_LIBRARY_PATH on MacOS), or copy the contents
|
||||
of those files to appropriate directories. Public include files
|
||||
(those needed when building applications that incorporate OSL)
|
||||
can be found in "dist/ARCH/include", and documentation can be found
|
||||
in "dist/ARCH/share/doc".
|
||||
can be found in "dist/include", and documentation can be found
|
||||
in "dist/share/doc".
|
||||
|
||||
6. After building (and setting your library path), you can run the
|
||||
test suite with:
|
||||
|
||||
@@ -393,6 +393,18 @@ Films using OSL (grouped by year of release date):
|
||||
Matrix Resurrections
|
||||
* **(2022 / upcoming)**
|
||||
Hotel Transylvania 4: Transformania,
|
||||
Death on the Nile,
|
||||
Uncharted,
|
||||
Turning Red,
|
||||
The Adam Project,
|
||||
Doctor Strange in the Multiverse of Madness,
|
||||
Love, Death, and Robots: In Vaulted Halls Entombed,
|
||||
Jurassic World: Dominion,
|
||||
Lightyear,
|
||||
Thor: Love and Thunder,
|
||||
The Sea Beast,
|
||||
DC League of Super Pets,
|
||||
Bullet Train,
|
||||
...
|
||||
|
||||
|
||||
@@ -427,9 +439,13 @@ certain is a legit problem in the code, and for which you can give clear
|
||||
instructions for how to reproduce, should be [reported as
|
||||
issues](https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/issues).
|
||||
|
||||
If confidentiality precludes a public question or issue, you may contact the
|
||||
project administrator privately at [lg@imageworks.com](lg@imageworks.com),
|
||||
including for security-related issues.
|
||||
If you think you've found a potential vulnerability in OSL, please
|
||||
confidentially report it by emailing the project administrators at
|
||||
[security@openshadinglanguage.org](security@openshadinglanguage.org).
|
||||
|
||||
If any other issue requires confidentiality that precludes a public question
|
||||
or issue, you may contact the project administrator privately at
|
||||
[lg@larrygritz.com](lg@larrygritz.com).
|
||||
|
||||
|
||||
Contributing
|
||||
@@ -453,7 +469,6 @@ Contacts, Links, and References
|
||||
|
||||
[OSL home page](http://openshadinglanguage.org)
|
||||
|
||||
[Sony Pictures Imageworks main open source page](http://opensource.imageworks.com)
|
||||
|
||||
|
||||
|
||||
@@ -466,19 +481,18 @@ 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, Syoyo Fujita,
|
||||
Tim Grant, Larry Gritz, Nicolas Guiard, Euan Haahr, Derek Haase, Sven-Hendrik
|
||||
Haase, John Haddon, Niklas Harrysson, Daniel Heckenberg, 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.)
|
||||
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
|
||||
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.)
|
||||
|
||||
We cannot possibly express sufficient gratitude to the managers at Sony
|
||||
Pictures Imageworks who allowed this project to proceed, supported it
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
This gives guidance about which branches are supported with patches to
|
||||
security vulnerabilities.
|
||||
|
||||
| Version / branch | Supported |
|
||||
| --------- | ---------------------------------------------------- |
|
||||
| main | :white_check_mark: :construction: ALL fixes immediately, but this is a branch under development with a frequently unstable ABI and occasionally unstable API. |
|
||||
| 1.12.x | :white_check_mark: All fixes that can be backported without breaking ABI compatibility. New tagged releases monthly. |
|
||||
| 1.11.x | :warning: Only the most critical fixes, only if they can be easily backported. |
|
||||
| <= 1.10.x | :x: No longer receiving patches of any kind. |
|
||||
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you think you've found a potential vulnerability in OSL, please report it
|
||||
by emailing the project administrators at
|
||||
[security@openshadinglanguage.org](security@openshadinglanguage.org). Only the
|
||||
project administrators have access to these messages. Include detailed steps to
|
||||
reproduce the issue, and any other information that could aid an
|
||||
investigation. Our policy is to respond to vulnerability reports within 14
|
||||
days.
|
||||
|
||||
Our policy is to address critical security vulnerabilities rapidly and post
|
||||
patches as quickly as possible.
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
The OSL Documentation Project is a work in progress.
|
||||
|
||||
The plan is to adopt the OCIO Documentation Project's methodology for maintaining and building documention of various kinds as it becomes the blueprint for the ASWF.
|
||||
The plan is to adopt the OCIO Documentation Project's methodology for maintaining and building documentation of various kinds as it becomes the blueprint for the ASWF.
|
||||
|
||||
There is much work to be done here.
|
||||
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
<!-- Copyright Contributors to the Open Shading Language Project. -->
|
||||
|
||||
# Release Procedures for Open Shading Language
|
||||
|
||||
## Version nomenclature and release cadence
|
||||
|
||||
### The meaning of the version parts
|
||||
|
||||
Our release numbers are of the form `MAJOR.MINOR.PATCH.TWEAK`, and we follow
|
||||
an almost-semantic-versioning scheme.
|
||||
|
||||
MAJOR changes are those that break backward-compatibility of the public APIs,
|
||||
requiring existing application code to change their source code where it calls
|
||||
OSL API functions in order to compile and work correctly.
|
||||
|
||||
MINOR changes guarantee API backward-compatibility with prior releases that
|
||||
have the same major number, but can introduce ABI or link incompatibilities.
|
||||
Applications using OSL need to be recompiled to move to a new minor release,
|
||||
but should not need to change their source code. Minor releases are allowed
|
||||
to drop support for sufficiently old compilers and dependencies.
|
||||
|
||||
PATCH changes guarantee both API and ABI/link backward-compatibility with
|
||||
prior releases that have the same minor number. Features and new public API
|
||||
calls may be added (thus deviating from strict semantic versioning), but only
|
||||
if they preserve ABI/link compatibility. This means that standalone functions
|
||||
or static methods may be added, but existing functions will not change their
|
||||
parameters, and no new virtual methods or struct data layouts change for patch
|
||||
releases (for classes in public header files). Application code can be
|
||||
re-linked to a new patch release without needing to be recompiled. We also
|
||||
guarantee that any compilers or dependencies supported for the first release
|
||||
of a minor series will continue to be supported for all patches to that minor
|
||||
series.
|
||||
|
||||
TWEAK changes are restricted to critical bug fixes or build breaks that do
|
||||
not alter public APIs in any way.
|
||||
|
||||
### Cadence of releases
|
||||
|
||||
Major (arbitrarily incompatible) releases happen rarely, usually with multiple
|
||||
years between them.
|
||||
|
||||
Minor (API backward-compatible) releases are scheduled annually, targeted at
|
||||
late summer (SIGGRAPH time) to be in beta, and early autumn for a full
|
||||
release.
|
||||
|
||||
Patch (API and ABI backward-compatible) releases are scheduled monthly,
|
||||
usually aiming for the first day of each month.
|
||||
|
||||
Tweak (fully forward and backward compatible) releases are not regularly
|
||||
scheduled, and only happen sporadically, when a critical fix is needed in
|
||||
between scheduled patch releases.
|
||||
|
||||
### Things are different in "main"
|
||||
|
||||
The "main" branch is where ongoing development occurs without any
|
||||
compatibility guarantees. We don't always know if the next year's release from
|
||||
main will turn out to be major (API breaking) or minor (only ABI breaking).
|
||||
|
||||
Some studios or products need the most up-to-date enhancements, and thus tend
|
||||
to build OSL from the "main" branch rather than using tagged releases. For
|
||||
these users, we try to set version numbers and occasionally tag in main, to
|
||||
send a signal about which points in main seem safe to rely on various
|
||||
compatibility levels. However, the rules are slightly different than we use
|
||||
for releases.
|
||||
|
||||
In the "main" branch:
|
||||
|
||||
- TWEAK changes within "main" only guarantee ABI back-compatibility, but may
|
||||
have additions or non-bug-fix behavior changes (akin to patch releases
|
||||
within a release branch).
|
||||
- PATCH changes within "main" are allowed to break ABI or API (changes that
|
||||
would require minor or major releases, if they were not in "main").
|
||||
- Beware of unmarked breaks in compatibility of commits in main that are
|
||||
in between developer preview tags.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Branch and tag names
|
||||
|
||||
**Branches** are places where commits containing new development may be added
|
||||
(and thus the branch markers will move over time). Branch names obey the
|
||||
following conventions:
|
||||
|
||||
- `main` is the area for arbitrary changes intended for the next year's major
|
||||
or minor release.
|
||||
- `dev-1.2` are the areas for staging additions to the next month's patch
|
||||
release for the designated minor version series.
|
||||
- `release` is a special branch marker that is always set to the latest tag of
|
||||
the currently supported, stable release family. People can count on
|
||||
"release" always being the latest stable release, whatever that may be at
|
||||
the time.
|
||||
|
||||
**Tags** indicate releases or developer previews, and once a commit is
|
||||
tagged, it is permanent and will never be moved. Tag names obey the following
|
||||
conventions:
|
||||
|
||||
- `v1.2.3.4` is a specific public stable release, corresponding to official
|
||||
major, minor, public, or tweak releases.
|
||||
- `v1.2.3.4-alpha`, `v1.2.3.4-beta`, or `v1.2.3.4-RC1` are pre-releases for an
|
||||
upcoming public stable release, at the alpha, beta, or release candidate
|
||||
stages, respectively.
|
||||
- `v1.2.3.4-dev` is a "developer preview" within "main." It is not an official
|
||||
supported release, and while the numbering may indicate compatibility versus
|
||||
other recent developer previews, they should not be assumed to be compatible
|
||||
with any prior official stable releases.
|
||||
|
||||
*Very* occasionally, other branch or tag names (with custom suffixes or
|
||||
different naming schemes) may be used for special purposes by particular
|
||||
developers or users, but should not be considered reliable or permanent, and
|
||||
in general should be ignored by anyone who didn't make the tag or branch.
|
||||
|
||||
---
|
||||
|
||||
## Release Procedures
|
||||
|
||||
### Soft freeze for monthly tweak releases:
|
||||
|
||||
We freely backport *safe*, non-ABI-breaking changes by cherry-picking them
|
||||
from main to the supported branch continually throughout most of the month.
|
||||
|
||||
In the seven days before the new month, we do a "soft freeze" where only
|
||||
important bug fixes are backported. Hold on to any other patches you wish to
|
||||
backport until after the monthly patch release (i.e., save them for the next
|
||||
month's release so you never have a release that contains changes that are
|
||||
only a few days old, and therefore not as well tested). You may, of course,
|
||||
continue to backport fixes to documentation or other non-code parts of the
|
||||
project during this soft freeze.
|
||||
|
||||
### Branching for annual major/minor releases
|
||||
|
||||
By mid-June (about 1-2 months before the beta of a new annual big release),
|
||||
you should branch and mark it as an alpha.
|
||||
|
||||
At the tip of "main," create a new branch named `dev-MAJOR.MINOR` that will be
|
||||
the staging area for the next release.
|
||||
|
||||
Customarily, at that point we add a commit to main (but not to the new
|
||||
dev-MAJ.MIN branch) that bumps main's version to the next minor level, to
|
||||
avoid any confusion between builds from main versus what will be the next
|
||||
release branch. This starts the divergence between main and the release
|
||||
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.)
|
||||
|
||||
|
||||
### Prior to a release
|
||||
|
||||
1. Update CI dependencies: Ensure that the "latest" CI test specifies the
|
||||
current releases of the dependencies and compilers (check their home
|
||||
pages), and that the [INSTALL.md](../INSTALL.md) file correctly documents
|
||||
the version ranges that we expect to work and that we actively test.
|
||||
|
||||
2. Release notes: [CHANGES.md](../CHANGES.md) should be updated to reflect
|
||||
all the new features and fixes. Looking at the notes from older releases
|
||||
should provide a good example of what we're aiming for.
|
||||
|
||||
- Patch and tweak releases can be brief one-line descriptions (often the
|
||||
first line of the commit messages involved), presented in a single
|
||||
section in either chronological or any other order that seems right.
|
||||
- Minor or major releases have a much more extensive, prose-based
|
||||
description of all changes since the last minor release, broken into
|
||||
sections (dependency changes, major new features, enhancements and fixes,
|
||||
internals and developer goodies, testing/CI/ports, etc.) and ordered for
|
||||
readability and relevance.
|
||||
|
||||
3. Ensure docs are up to date:
|
||||
|
||||
- Actually read the [README.md](../README.md), [INSTALL.md](../INSTALL.md),
|
||||
and other repository docs and make sure all the information is up to
|
||||
date. Check the "contributor credits" in the README against the recent
|
||||
repo history to be sure new contributors are listed. Also check the
|
||||
list of films and make sure it includes any recent productions that are
|
||||
known to have used OSL.
|
||||
- Skim the primary user documentation to look for any obvious errors,
|
||||
especially the parts that describe new features. In the case of PDF docs
|
||||
(such as osl-languagespec.pdf), make sure that a new PDF book is built if
|
||||
the documentation source has been changed since the last release.
|
||||
- If we are using any online docs (like readthedocs), make sure it is
|
||||
building and looks correct on the web site.
|
||||
|
||||
4. Make sure the the top-level CMakeLists.txt file is updated:
|
||||
|
||||
- The version on the `project()` call should be correct.
|
||||
- The `PROJECT_VERSION_RELEASE_TYPE` variable should be set to "alpha" or
|
||||
"beta" if appropriate, "RC" for release candidate, or empty string `""`
|
||||
for most supported releases, and "dev" only for the main branch or
|
||||
developer previews.
|
||||
- The `${PROJECT_NAME}_SUPPORTED_RELEASE` variable should be `ON` for any
|
||||
release branch, `OFF` for main.
|
||||
|
||||
5. Make sure everything passes the usual CI workflow. Also check the daily or
|
||||
weekly "analysis" workflows to make sure there aren't any important
|
||||
warnings that should be fixed.
|
||||
|
||||
|
||||
### Staging alpha / beta / release candidate (annual minor/major releases only)
|
||||
|
||||
For monthly patch releases, we don't have any formal alpha/beta/RC stages.
|
||||
|
||||
For the annual minor or major releases we have a staged release:
|
||||
|
||||
- `alpha` is everything after we have branched, in which we think all the big
|
||||
new features have been added, and while we will make continued changes and
|
||||
fixes, we are aiming for increased stability and to minimize additional
|
||||
breaking changes prior to the release.
|
||||
- `beta` should be about one month prior to the final release date. We create
|
||||
a tag `v1.2.3.4-beta` and announce the beta (see below "Making the
|
||||
release"). Once we tag a beta, we try very hard not to allow any further
|
||||
changes that change the API or are not ABI-compatible (i.e., safe fixes
|
||||
only).
|
||||
- `RC` or release candidates around one week prior to the final release date.
|
||||
This is a trial run, hopefully identical to the final release (except for
|
||||
removing the RC label and making a new tag). The only changes allowed after
|
||||
RC are fixes to the most critical bugs or build breaks that would be bad for
|
||||
users to encounter. If critical problems are found with RC1, they should be
|
||||
fixed and immediately re-tagged as RC2, etc. All other fixes should be
|
||||
postponed until the next month's patch release.
|
||||
|
||||
### Making the release
|
||||
|
||||
A final release is made on the scheduled date, provided the latest RC has
|
||||
survived for at least a few days of testing without finding any critical
|
||||
problems. Don't make the release final until you are sure there are no
|
||||
truly critical bugs or build breaks that users will encounter.
|
||||
|
||||
The following are the steps for making the release:
|
||||
|
||||
1. Edit the top-level CMakeLists.txt to remove any RC designation
|
||||
(i.e., `PROJECT_VERSION_RELEASE_TYPE` should be set to `""`).
|
||||
|
||||
2. Edit CHANGES.md to reflect the correct date of the release and ensure it
|
||||
includes any last-minute changes that were made during beta or release
|
||||
candidate stages.
|
||||
|
||||
3. Push it to **your** GitHub, make sure it passes CI.
|
||||
|
||||
4. Tag the release: `git tag v1.2.3.4` (no more beta, RC, or dev suffix).
|
||||
|
||||
5. If this will now be the recommended stable release, move the `release`
|
||||
branch marker to the same position.
|
||||
|
||||
6. Push it to GitHub: `git push aswf release --tags`
|
||||
|
||||
(This example assumes "aswf" is the name of the remote for the GitHub
|
||||
`AcademySoftwareFoundation/OpenShadingLanguage` repo.)
|
||||
|
||||
7. Draft a release on GitHub: On
|
||||
https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/releases
|
||||
select "Draft a new release." Choose the new tag you just pushed. Make the
|
||||
release title "Open Shading Language v1.2.3.4" (and beta, etc., designation
|
||||
if applicable). In the description, paste the release notes for this
|
||||
release (from Changes.md). If this is a beta or release candidate, check
|
||||
"this is a pre-release" box at the bottom.
|
||||
|
||||
8. Announce the release on the [osl-dev mail list](https://lists.aswf.io/g/osl-dev)
|
||||
with the subject "Release: OSL v1.2.3.4" and using one of these templates
|
||||
for the body of the email.
|
||||
|
||||
For a monthly patch release:
|
||||
|
||||
> We have tagged v1.2.3.4 as the latest production release and moved the
|
||||
> "release" branch marker to that point. This is guaranteed to be API,
|
||||
> ABI, and link back-compatible with prior 1.2 releases. Release notes
|
||||
> are below.
|
||||
>
|
||||
> (Paste the full set of 1.2 changes here, just copy the appropriate
|
||||
> part of CHANGES.md)
|
||||
|
||||
For an annual major/minor release:
|
||||
|
||||
> OSL version 1.2 has been released! Officially tagged as "v1.2.3.4", we
|
||||
> have also moved the "release" branch tag to this position. Henceforth,
|
||||
> 1.2 is the supported production release family. The API is now frozen --
|
||||
> we promise that subsequent 1.2.x releases (which should happen monthly)
|
||||
> will not break back-compatibility of API, ABI, or linkage, compared to
|
||||
> this release. Please note that this release is *not* ABI or link
|
||||
> compatible with 1.1 or older releases.
|
||||
>
|
||||
> Release notes for 1.2 outlining all the changes since last year's
|
||||
> release are below.
|
||||
>
|
||||
> Please note that a few of the build and runtime dependencies have
|
||||
> changed their minimum supported versions. (List here any important
|
||||
> changes to dependencies, compilers, or C++ standard that users should be
|
||||
> aware of.)
|
||||
>
|
||||
> (List here anything else that people should know about this release
|
||||
> family that may be surprising if they haven't followed the last year of
|
||||
> development closely, or that they must know even if they are too lazy to
|
||||
> read the release notes. If this is a major release that is not
|
||||
> backward-compatible with prior versions, warn about that here.)
|
||||
>
|
||||
> Enjoy, and please report any problems. We will continue to make patch
|
||||
> releases to the 1.2 family roughly monthly, which will contain bug fixes
|
||||
> and non-breaking enhancements.
|
||||
>
|
||||
> The older 1.1 series of releases is now considered obsolete. We will
|
||||
> continue for now to make 1.1 patch releases, but over time, these will
|
||||
> become less frequent and be reserved for only the most critical bug
|
||||
> fixes.
|
||||
>
|
||||
> The "main" branch is now progressing toward an eventual 1.3 release next
|
||||
> summer. As usual, you are welcome to use main for real work, but we do
|
||||
> not make any compatibility guarantees and don't guarantee continuing API
|
||||
> compatibility in main.
|
||||
>
|
||||
> (Paste the full set of 1.2 changes here, just copy the appropriate
|
||||
> part of CHANGES.md)
|
||||
|
||||
For a beta leading up to the annual major/minor release:
|
||||
|
||||
> OSL version 1.2 is now in beta, tagged as "v1.2.3.4-beta". We
|
||||
> will try very hard not to make any further API or ABI changes between
|
||||
> now and the final release (unless it is absolutely necessary to fix
|
||||
> an important problem identified during beta testing). The final 1.2
|
||||
> release is scheduled for [DATE GOES HERE], so please try building and
|
||||
> testing the beta so we are sure to find any problems.
|
||||
>
|
||||
> Release notes for 1.2 outlining all the changes since last year's
|
||||
> release are below.
|
||||
>
|
||||
> (Paste the full set of 1.2 changes here, just copy the appropriate
|
||||
> part of CHANGES.md)
|
||||
|
||||
|
||||
### After the release
|
||||
|
||||
Odds and ends to do after the tag is pushed and the announcements are sent:
|
||||
|
||||
- Re-read RELEASING.md and ensure that the instructions match what you
|
||||
have done. Update as necessary.
|
||||
|
||||
- For annual beta releases, post a short message to the "Open Shading
|
||||
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.
|
||||
|
||||
|
||||
@@ -181,14 +181,14 @@ else ifeq (${platform}, macosx)
|
||||
MY_CMAKE_FLAGS += \
|
||||
-DCMAKE_C_COMPILER=gcc-9 -DCMAKE_CXX_COMPILER=g++-9
|
||||
USE_LIBCPLUSPLUS := 0
|
||||
else ifeq (${COMPILER},clang11)
|
||||
else ifeq (${COMPILER},clang14)
|
||||
MY_CMAKE_FLAGS += \
|
||||
-DCMAKE_C_COMPILER=/usr/local/opt/llvm@11/bin/clang \
|
||||
-DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@11/bin/clang++
|
||||
else ifeq (${COMPILER},clang12)
|
||||
-DCMAKE_C_COMPILER=/usr/local/opt/llvm@14/bin/clang \
|
||||
-DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@14/bin/clang++
|
||||
else ifeq (${COMPILER},clang15)
|
||||
MY_CMAKE_FLAGS += \
|
||||
-DCMAKE_C_COMPILER=/usr/local/opt/llvm@12/bin/clang \
|
||||
-DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@12/bin/clang++
|
||||
-DCMAKE_C_COMPILER=/usr/local/opt/llvm@15/bin/clang \
|
||||
-DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@15/bin/clang++
|
||||
else ifeq (${COMPILER},clang)
|
||||
MY_CMAKE_FLAGS += -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
else ifeq (${COMPILER},gcc)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Copyright Contributors to the Open Shading Language Project.
|
||||
|
||||
sonar.host.url=https://sonarcloud.io
|
||||
|
||||
# Required metadata
|
||||
sonar.organization=academysoftwarefoundation
|
||||
sonar.projectName=OpenShadingLanguage
|
||||
sonar.projectVersion=1.12
|
||||
sonar.projectKey=AcademySoftwareFoundation_OpenShadingLanguage
|
||||
|
||||
# Project links
|
||||
sonar.links.homepage=https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
sonar.links.ci=https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/actions
|
||||
sonar.links.scm=https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
sonar.links.issue=https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/issues
|
||||
|
||||
# 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
|
||||
sonar.cfamily.gcov.reportsPath=_coverage
|
||||
|
||||
sonar.cfamily.cache.enabled=true
|
||||
sonar.cfamily.cache.path=/tmp/sonarcache
|
||||
@@ -29,7 +29,10 @@ if [[ `uname` == "Linux" ]] ; then
|
||||
fi
|
||||
LLVMTAR=clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-${LLVM_DISTRO_NAME}.tar.xz
|
||||
echo LLVMTAR = $LLVMTAR
|
||||
if [[ "$LLVM_VERSION" == "10.0.0" ]] || [[ "$LLVM_VERSION" == "11.0.0" ]] || [[ "$LLVM_VERSION" == "11.1.0" ]] || [[ "$LLVM_VERSION" == "12.0.0" ]] || [[ "$LLVM_VERSION" == "13.0.0" ]] || [[ "$LLVM_VERSION" == "14.0.0" ]] || [[ "$LLVM_VERSION" == "14.0.1" ]] ; then
|
||||
if [[ "$LLVM_VERSION" == "10.0.0" ]] || [[ "$LLVM_VERSION" == "11.0.0" ]] \
|
||||
|| [[ "$LLVM_VERSION" == "11.1.0" ]] || [[ "$LLVM_VERSION" == "12.0.0" ]] \
|
||||
|| [[ "$LLVM_VERSION" == "13.0.0" ]] || [[ "$LLVM_VERSION" == "14.0.0" ]] ;
|
||||
then
|
||||
# new
|
||||
curl --location https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/${LLVMTAR} -o $LLVMTAR
|
||||
else
|
||||
|
||||
@@ -12,6 +12,10 @@ if [[ "$USE_SIMD" != "" ]] ; then
|
||||
OSL_CMAKE_FLAGS="$OSL_CMAKE_FLAGS -DUSE_SIMD=$USE_SIMD"
|
||||
fi
|
||||
|
||||
if [[ -n "$CODECOV" ]] ; then
|
||||
OSL_CMAKE_FLAGS="$OSL_CMAKE_FLAGS -DCODECOV=${CODECOV}"
|
||||
fi
|
||||
|
||||
pushd build
|
||||
cmake .. -G "$CMAKE_GENERATOR" \
|
||||
-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \
|
||||
@@ -23,7 +27,16 @@ cmake .. -G "$CMAKE_GENERATOR" \
|
||||
-DCMAKE_INSTALL_LIBDIR="$OSL_ROOT/lib" \
|
||||
-DCMAKE_CXX_STANDARD="$CMAKE_CXX_STANDARD" \
|
||||
$OSL_CMAKE_FLAGS -DVERBOSE=1
|
||||
time cmake --build . --target ${BUILDTARGET:=install} --config ${CMAKE_BUILD_TYPE}
|
||||
|
||||
# Save a copy of the generated files for debugging broken CI builds.
|
||||
mkdir cmake-save || /bin/true
|
||||
cp -r CMake* *.cmake cmake-save
|
||||
|
||||
: ${BUILDTARGET:=install}
|
||||
if [[ "$BUILDTARGET" != "none" ]] ; then
|
||||
echo "Parallel build ${CMAKE_BUILD_PARALLEL_LEVEL} of target ${BUILDTARGET}"
|
||||
time ${OSL_CMAKE_BUILD_WRAPPER} cmake --build . --target ${BUILDTARGET} --config ${CMAKE_BUILD_TYPE}
|
||||
fi
|
||||
popd
|
||||
|
||||
if [[ "${DEBUG_CI:=0}" != "0" ]] ; then
|
||||
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Run code coverage analysis
|
||||
# This assumes that the build occurred with CODECOV=1 andtests have already
|
||||
# fully run.
|
||||
|
||||
set -ex
|
||||
|
||||
echo "Performing code coverage analysis"
|
||||
mkdir _coverage
|
||||
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:
|
||||
# ../src/liboslexec/foo.cpp
|
||||
|
||||
for g in $(find ../build -name "*.gcno" -type f); do
|
||||
echo "Processing $g"
|
||||
echo "dirname $g = $(dirname $g) to " `$(echo "$g" | sed -e 's/\/build\//\//' -e 's/\.gcno/\.cpp/' -e 's/\.cpp\.cpp/\.cpp/' -e 's/\/CMakeFiles.*\.dir\//\//')`
|
||||
gcov -l -p -o $(dirname "$g") $(echo "$g" | sed -e 's/\/build\//\//' -e 's/\.gcno/\.cpp/' -e 's/\/CMakeFiles.*\.dir\//\//')
|
||||
done
|
||||
popd
|
||||
@@ -23,7 +23,7 @@ export DYLD_LIBRARY_PATH=$OSL_ROOT/lib:$DYLD_LIBRARY_PATH
|
||||
export LD_LIBRARY_PATH=$OSL_ROOT/lib:$LD_LIBRARY_PATH
|
||||
export OIIO_LIBRARY_PATH=$OSL_ROOT/lib:${OIIO_LIBRARY_PATH}
|
||||
export LSAN_OPTIONS=suppressions=$PWD/src/build-scripts/nosanitize.txt
|
||||
export ASAN_OPTIONS=print_suppressions=0
|
||||
export ASAN_OPTIONS=print_suppressions=0:detect_odr_violation=1
|
||||
|
||||
export USE_PYTHON=${USE_PYTHON:=1}
|
||||
export PYTHON_VERSION=${PYTHON_VERSION:="2.7"}
|
||||
@@ -61,6 +61,7 @@ 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
|
||||
|
||||
@@ -8,12 +8,26 @@
|
||||
# any command in it fails. This is crucial for CI tests.
|
||||
set -ex
|
||||
|
||||
: ${CTEST_EXCLUSIONS:="broken"}
|
||||
: ${CTEST_TEST_TIMEOUT:=60}
|
||||
|
||||
$OSL_ROOT/bin/testshade --help
|
||||
|
||||
echo "Parallel test " ${CTEST_PARALLEL_LEVEL}
|
||||
echo "Parallel test ${CTEST_PARALLEL_LEVEL}"
|
||||
echo "Default timeout ${CTEST_TEST_TIMEOUT}"
|
||||
echo "Test exclusions '${CTEST_EXCLUSIONS}'"
|
||||
echo "CTEST_ARGS '${CTEST_ARGS}'"
|
||||
|
||||
pushd build
|
||||
time ctest -C ${CMAKE_BUILD_TYPE} -E broken --force-new-ctest-process \
|
||||
--output-on-failure --timeout ${CTEST_TEST_TIMEOUT:=60} ${CTEST_ARGS}
|
||||
|
||||
ctest -C ${CMAKE_BUILD_TYPE} --force-new-ctest-process --output-on-failure \
|
||||
--timeout ${CTEST_TEST_TIMEOUT} -E "${CTEST_EXCLUSIONS}" ${CTEST_ARGS} \
|
||||
|| \
|
||||
ctest -C ${CMAKE_BUILD_TYPE} --force-new-ctest-process \
|
||||
--rerun-failed --repeat until-pass:5 -R render --output-on-failure \
|
||||
--timeout ${CTEST_TEST_TIMEOUT} -E "${CTEST_EXCLUSIONS}" ${CTEST_ARGS}
|
||||
# The weird construct above allows the render-* tests to run multiple times
|
||||
|
||||
popd
|
||||
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ from __future__ import print_function, absolute_import
|
||||
###
|
||||
### Only one main doc region will be output by the `docdeep` program,
|
||||
### specified with the `-d` command line argument. Any other doc-regions
|
||||
### will not be included in the documention output of that run.
|
||||
### will not be included in the documentation output of that run.
|
||||
###
|
||||
### However, one doc-region may *include* the text of another doc-region
|
||||
### as follows:
|
||||
@@ -114,7 +114,7 @@ from __future__ import print_function, absolute_import
|
||||
### For pre-code comments, the contiguous comment region associated with
|
||||
### a declaration immediately precedes the declaration. Such a comment
|
||||
### set has its first line start with `///>`. For post-code comments,
|
||||
### the documentaiton comments follows the code declaration, and this is
|
||||
### the documentation comments follows the code declaration, and this is
|
||||
### designated by having its first line start with `///<`. I like to
|
||||
### just remember that the `<` or `>` points in the direction of the code
|
||||
### declaration that the comment applies to.
|
||||
|
||||
@@ -42,8 +42,12 @@ 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
|
||||
set +e; source /opt/intel/oneapi/setvars.sh; set -e
|
||||
sudo yum install -y intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic-2022.1.0-3768
|
||||
# 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.
|
||||
set +e; source /opt/intel/oneapi/setvars.sh --config oneapi_2022.1.0.cfg; set -e
|
||||
|
||||
if [[ "$CXX" == "icpc" || "$CC" == "icc" || "$USE_ICC" != "" ]] ; then
|
||||
echo "Verifying installation of Intel(r) C++ Compiler:"
|
||||
icpc --version
|
||||
@@ -64,15 +68,27 @@ else
|
||||
git cmake ninja-build ccache g++ \
|
||||
libboost-dev libboost-thread-dev libboost-filesystem-dev \
|
||||
libilmbase-dev libopenexr-dev \
|
||||
python-dev python-numpy \
|
||||
libtiff-dev libgif-dev libpng-dev \
|
||||
flex bison libbison-dev \
|
||||
libpugixml-dev \
|
||||
libopencolorio-dev \
|
||||
qt5-default
|
||||
libopencolorio-dev
|
||||
|
||||
time sudo apt-get -q install -y \
|
||||
qt5-default || /bin/true
|
||||
|
||||
export CMAKE_PREFIX_PATH=/usr/lib/x86_64-linux-gnu:$CMAKE_PREFIX_PATH
|
||||
|
||||
# Nonstandard python versions
|
||||
if [[ "${PYTHON_VERSION}" == "3.9" ]] ; then
|
||||
time sudo apt-get -q install -y python3.9-dev python3-numpy
|
||||
pip3 --version
|
||||
pip3 install numpy
|
||||
elif [[ "$PYTHON_VERSION" == "2.7" ]] ; then
|
||||
time sudo apt-get -q install -y python-dev python-numpy
|
||||
else
|
||||
pip3 install numpy
|
||||
fi
|
||||
|
||||
if [[ "$CXX" == "g++-6" ]] ; then
|
||||
time sudo apt-get install -y g++-6
|
||||
elif [[ "$CXX" == "g++-7" ]] ; then
|
||||
@@ -85,6 +101,8 @@ else
|
||||
time sudo apt-get install -y g++-10
|
||||
elif [[ "$CXX" == "g++-11" ]] ; then
|
||||
time sudo apt-get install -y g++-11
|
||||
elif [[ "$CXX" == "g++-12" ]] ; then
|
||||
time sudo apt-get install -y g++-12
|
||||
fi
|
||||
|
||||
if [[ "$CXX" == "icpc" || "$CC" == "icc" || "$USE_ICC" != "" || "$CXX" == "icpx" || "$CC" == "icx" || "$USE_ICX" != "" ]] ; then
|
||||
@@ -92,22 +110,11 @@ else
|
||||
sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB
|
||||
echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list
|
||||
time sudo apt-get update
|
||||
time sudo apt-get install -y intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic
|
||||
set +e; source /opt/intel/oneapi/setvars.sh; set -e
|
||||
if [[ "$CXX" == "icpc" || "$CC" == "icc" || "$USE_ICC" != "" ]] ; then
|
||||
icpc --version
|
||||
fi
|
||||
if [[ "$CXX" == "icpx" || "$CC" == "icx" || "$USE_ICX" != "" ]] ; then
|
||||
icpx --version
|
||||
fi
|
||||
fi
|
||||
|
||||
# Nonstandard python versions
|
||||
if [[ "${PYTHON_VERSION}" == "3.8" ]] ; then
|
||||
#time sudo apt-get -q install -y python3.8-dev python3-numpy
|
||||
echo "skip?"
|
||||
elif [[ "${PYTHON_VERSION}" == "3.9" ]] ; then
|
||||
time sudo apt-get -q install -y python3.9-dev python3-numpy
|
||||
time sudo apt-get install -y intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic=2022.1.0-3768
|
||||
# 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.
|
||||
set +e; source /opt/intel/oneapi/setvars.sh --config oneapi_2022.1.0.cfg; set -e
|
||||
fi
|
||||
|
||||
source src/build-scripts/build_llvm.bash
|
||||
@@ -150,14 +157,26 @@ if [[ "$OPENCOLORIO_VERSION" != "" ]] ; then
|
||||
fi
|
||||
|
||||
if [[ "$OPENIMAGEIO_VERSION" != "" ]] ; then
|
||||
# There are many parts of OIIO we don't need to build
|
||||
# There are many parts of OIIO we don't need to build for OSL's tests
|
||||
export ENABLE_iinfo=0 ENABLE_iv=0 ENABLE_igrep=0
|
||||
export ENABLE_iconvert=0 ENABLE_testtex=0
|
||||
# For speed of compiling OIIO, disable the file formats that we don't
|
||||
# need for OSL's tests
|
||||
export ENABLE_BMP=0 ENABLE_cineon=0 ENABLE_DDS=0 ENABLE_DPX=0 ENABLE_FITS=0
|
||||
export ENABLE_ICO=0 ENABLE_iff=0 ENABLE_jpeg2000=0 ENABLE_PNM=0 ENABLE_PSD=0
|
||||
export ENABLE_RLA=0 ENABLE_SGI=0 ENABLE_SOCKET=0 ENABLE_SOFTIMAGE=0
|
||||
export ENABLE_TARGA=0 ENABLE_WEBP=0
|
||||
export OPENIMAGEIO_CMAKE_FLAGS+=" -DOIIO_BUILD_TESTS=0 -DUSE_OPENGL=0"
|
||||
# We don't need to run OIIO's tests
|
||||
export OPENIMAGEIO_CMAKE_FLAGS+=" -DOIIO_BUILD_TESTING=OFF -DOIIO_BUILD_TESTS=0"
|
||||
# Don't let warnings in OIIO break OSL's CI run
|
||||
export OPENIMAGEIO_CMAKE_FLAGS+=" -DSTOP_ON_WARNING=OFF"
|
||||
export OPENIMAGEIO_CMAKE_FLAGS+=" -DUSE_OPENGL=0"
|
||||
if [[ $OPENIMAGEIO_VERSION == master && "${OPENIMAGEIO_UNITY:-1}" != "0" ]] ; then
|
||||
# Speed up the OIIO build by doing a "unity" build. (Note: this is
|
||||
# only a savings in CI where there are only 1-2 cores available, and
|
||||
# is only supported for OIIO 2.3.14 and later)
|
||||
export OPENIMAGEIO_CMAKE_FLAGS+=" -DCMAKE_UNITY_BUILD=ON -DCMAKE_UNITY_BUILD_MODE=BATCH"
|
||||
fi
|
||||
source src/build-scripts/build_openimageio.bash
|
||||
fi
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
|
||||
# This script, which assumes it is runnign on a Mac OSX with Homebrew
|
||||
# This script, which assumes it is running on a Mac OSX with Homebrew
|
||||
# installed, does a "brew install" in all packages reasonably needed by
|
||||
# OSL and its dependencies.
|
||||
|
||||
@@ -20,16 +20,20 @@ if [[ `which brew` == "" ]] ; then
|
||||
fi
|
||||
|
||||
|
||||
#brew update >/dev/null
|
||||
if [[ "$DO_BREW_UPDATE" != "" ]] ; then
|
||||
brew update >/dev/null
|
||||
fi
|
||||
echo ""
|
||||
echo "Before my brew installs:"
|
||||
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.9 || 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
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
leak:Imf_2_2
|
||||
leak:Imf_2_3
|
||||
leak:Imf_2_4
|
||||
leak:libIlmImf
|
||||
leak:oslgram.y
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
default=exclude
|
||||
compiler=2022.1.0
|
||||
tbb=2021.6.0
|
||||
Regular → Executable
+1
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright Contributors to the Open Shading Language project.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
@@ -22,7 +22,7 @@ find_dependency(OpenImageIO @OpenImageIO_VERSION@ REQUIRED)
|
||||
# Compute the installation prefix relative to this file
|
||||
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
|
||||
|
||||
# There's no guarantee that CMAKE_INSTALL_XXXDIR is a relative path so we extract the final component to handle asbolute paths
|
||||
# There's no guarantee that CMAKE_INSTALL_XXXDIR is a relative path so we extract the final component to handle absolute paths
|
||||
get_filename_component(_INCLUDE_DIR_NAME "@CMAKE_INSTALL_INCLUDEDIR@" NAME)
|
||||
get_filename_component(_LIB_DIR_NAME "@CMAKE_INSTALL_LIBDIR@" NAME)
|
||||
|
||||
|
||||
+22
-49
@@ -68,9 +68,9 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER MATCHES "[Cc]lan
|
||||
endif ()
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "IntelLLVM")
|
||||
set (CMAKE_COMPILER_IS_INTELCLANG 1)
|
||||
string (REGEX REPLACE ".* version ([0-9]+\\.[0-9]+).*" "\\1" CLANG_VERSION_STRING ${clang_full_version_string})
|
||||
string (REGEX MATCH "[0-9]+(\\.[0-9]+)+" INTELCLANG_VERSION_STRING ${clang_full_version_string})
|
||||
if (VERBOSE)
|
||||
message (STATUS "The compiler is Intel Clang: ${CMAKE_CXX_COMPILER_ID} version ${CLANG_VERSION_STRING}")
|
||||
message (STATUS "The compiler is Intel Clang: ${CMAKE_CXX_COMPILER_ID} version ${INTELCLANG_VERSION_STRING}")
|
||||
endif ()
|
||||
else ()
|
||||
string (REGEX REPLACE ".* version ([0-9]+\\.[0-9]+).*" "\\1" CLANG_VERSION_STRING ${clang_full_version_string})
|
||||
@@ -162,6 +162,13 @@ if (CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_APPLECLANG)
|
||||
# Don't warn about using unknown preprocessor symbols in `#if`
|
||||
add_compile_options ("-Wno-expansion-to-defined")
|
||||
endif ()
|
||||
# Suppress warnings about our strategic use of bitwise operations in place
|
||||
# of logical operators to produce branchless code in some places.
|
||||
if (CLANG_VERSION_STRING VERSION_GREATER_EQUAL 14.0
|
||||
OR INTELCLANG_VERSION_STRING VERSION_GREATER_EQUAL 14.0)
|
||||
add_compile_options ("-Wno-bitwise-instead-of-logical")
|
||||
endif ()
|
||||
|
||||
# disable warning in flex-generated code
|
||||
add_compile_options ("-Wno-null-conversion")
|
||||
add_compile_options ("-Wno-error=strict-overflow")
|
||||
@@ -189,6 +196,11 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
|
||||
add_compile_options ("-fno-math-errno")
|
||||
endif ()
|
||||
|
||||
if (INTELCLANG_VERSION_STRING VERSION_GREATER_EQUAL 2022.1.0)
|
||||
# New versions of icx warn about changing certain floating point options
|
||||
add_compile_options ("-Wno-overriding-t-option")
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
# Microsoft specific options
|
||||
string (REGEX REPLACE "/W[1-4]" "/W1" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
@@ -214,7 +226,7 @@ endif ()
|
||||
|
||||
|
||||
|
||||
# We wil use this for ccache and timing
|
||||
# We will use this for ccache and timing
|
||||
set (MY_RULE_LAUNCH "")
|
||||
|
||||
|
||||
@@ -364,11 +376,9 @@ include (CheckCXXSourceRuns)
|
||||
option (CODECOV "Build code coverage tests" OFF)
|
||||
if (CODECOV AND (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG))
|
||||
message (STATUS "Compiling for code coverage analysis")
|
||||
add_compile_options ("-ftest-coverage -fprofile-arcs -O0")
|
||||
add_compile_options (-ftest-coverage -fprofile-arcs)
|
||||
add_definitions ("-D${PROJ_NAME}_CODE_COVERAGE=1")
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -ftest-coverage -fprofile-arcs")
|
||||
set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -ftest-coverage -fprofile-arcs")
|
||||
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -ftest-coverage -fprofile-arcs")
|
||||
link_libraries(gcov)
|
||||
endif ()
|
||||
|
||||
|
||||
@@ -382,22 +392,9 @@ if (SANITIZE AND (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG))
|
||||
foreach (feature ${SANITIZE_FEATURE_LIST})
|
||||
message (STATUS " sanitize feature: ${feature}")
|
||||
add_compile_options (-fsanitize=${feature})
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=${feature}")
|
||||
set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=${feature}")
|
||||
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=${feature}")
|
||||
add_link_options (-fsanitize=${feature})
|
||||
endforeach()
|
||||
add_compile_options (-g -fno-omit-frame-pointer)
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set (SANITIZE_ON_LINUX 1)
|
||||
endif ()
|
||||
if (CMAKE_COMPILER_IS_GNUCC AND ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
add_compile_options ("-fuse-ld=gold")
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
|
||||
set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fuse-ld=gold")
|
||||
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=gold")
|
||||
set (SANITIZE_LIBRARIES "asan;pthread")
|
||||
# set (SANITIZE_LIBRARIES "asan" "ubsan")
|
||||
endif()
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
# turn on glibcxx extra annotations to find vector writes past end
|
||||
add_definitions ("-D_GLIBCXX_SANITIZE_VECTOR=1")
|
||||
@@ -463,41 +460,17 @@ endif ()
|
||||
# is being built as a subproject.
|
||||
if (PROJECT_IS_TOP_LEVEL)
|
||||
set (CLANG_FORMAT_EXE_HINT "" CACHE PATH "clang-format executable's directory (will search if not specified")
|
||||
set (CLANG_FORMAT_INCLUDES # "src/*.h" "src/*.cpp"
|
||||
"src/include/*.h"
|
||||
"src/liboslcomp/*.cpp"
|
||||
"src/liboslcomp/*.h"
|
||||
"src/liboslexec/batched_rendservices.cpp"
|
||||
"src/liboslquery/*.cpp"
|
||||
"src/liboslquery/*.h"
|
||||
"src/oslinfo/*.cpp"
|
||||
"src/oslc/*.cpp"
|
||||
"src/osl.imageio/*.cpp"
|
||||
"src/osltoy/*.cpp"
|
||||
"src/osltoy/*.h"
|
||||
"testsuite/*.cpp"
|
||||
set (CLANG_FORMAT_INCLUDES "src/*.cpp" "src/*.h" "src/*.cu"
|
||||
CACHE STRING "Glob patterns to include for clang-format")
|
||||
set (CLANG_FORMAT_EXCLUDES
|
||||
# Files "imported and modified" that we don't want to reformat, so
|
||||
# they continue to match their upstream versions.
|
||||
"src/include/OSL/Imathx/*"
|
||||
"src/include/OSL/matrix22.h"
|
||||
# Files that are currently being modified with the SIMD batch
|
||||
# shading -- we'll reformat those only after that project work is
|
||||
# completed, to avoid nasty merge conflicts.
|
||||
"src/include/OSL/rendererservices.h"
|
||||
"src/include/OSL/*llvm*"
|
||||
"src/liboslexec/*llvm*"
|
||||
"src/liboslexec/oslexec_pvt.h"
|
||||
# Files that are currently being modified with the OptiX work --
|
||||
# we'll reformat those only after that project work is completed, to
|
||||
# avoid nasty merge conflicts.
|
||||
"src/include/OSL/device_string.h"
|
||||
"src/include/OSL/oslexec.h"
|
||||
"src/testrender/cuda/*"
|
||||
# Header files in testsuite are almost certainly osl headers, not C++
|
||||
"testsuite/*.h"
|
||||
""
|
||||
# Header files in shaders are OSL, not C++
|
||||
"src/shaders/*.h"
|
||||
CACHE STRING "Glob patterns to exclude for clang-format")
|
||||
find_program (CLANG_FORMAT_EXE
|
||||
NAMES clang-format bin/clang-format
|
||||
@@ -518,7 +491,7 @@ if (PROJECT_IS_TOP_LEVEL)
|
||||
# message (STATUS "clang-format file list: ${FILES_TO_FORMAT}")
|
||||
file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/.clang-format
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_custom_target (run-clang-format
|
||||
add_custom_target (clang-format
|
||||
COMMAND "${CLANG_FORMAT_EXE}" -i -style=file ${FILES_TO_FORMAT} )
|
||||
else ()
|
||||
message (STATUS "clang-format not found.")
|
||||
|
||||
@@ -80,6 +80,20 @@ function ( MAKE_CUDA_BITCODE src suffix generated_bc extra_clang_args )
|
||||
message (STATUS "Using LLVM_BC_GENERATOR ${LLVM_BC_GENERATOR} to generate bitcode.")
|
||||
endif()
|
||||
|
||||
if (NOT LLVM_AS_TOOL)
|
||||
find_program (LLVM_AS_TOOL NAMES "llvm-as"
|
||||
PATHS "${LLVM_DIRECTORY}/bin" "${LLVM_DIRECTORY}/tools/llvm"
|
||||
NO_CMAKE_PATH NO_DEFAULT_PATH NO_CMAKE_SYSTEM_PATH
|
||||
NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_ENVIRONMENT_PATH)
|
||||
endif ()
|
||||
|
||||
if (NOT LLVM_LINK_TOOL)
|
||||
find_program (LLVM_LINK_TOOL NAMES "llvm-link"
|
||||
PATHS "${LLVM_DIRECTORY}/bin" "${LLVM_DIRECTORY}/tools/llvm"
|
||||
NO_CMAKE_PATH NO_DEFAULT_PATH NO_CMAKE_SYSTEM_PATH
|
||||
NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_ENVIRONMENT_PATH)
|
||||
endif ()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
# fix compilation error when using MSVC
|
||||
set (CLANG_MSVC_FIX "-DBOOST_CONFIG_REQUIRES_THREADS_HPP")
|
||||
@@ -115,7 +129,7 @@ function ( MAKE_CUDA_BITCODE src suffix generated_bc extra_clang_args )
|
||||
-Wno-deprecated-register -Wno-format-security
|
||||
-O3 -fno-math-errno -ffast-math -S -emit-llvm ${extra_clang_args}
|
||||
${src} -o ${asm_cuda}
|
||||
COMMAND "${LLVM_DIRECTORY}/bin/llvm-as" -f -o ${bc_cuda} ${asm_cuda}
|
||||
COMMAND ${LLVM_AS_TOOL} -f -o ${bc_cuda} ${asm_cuda}
|
||||
DEPENDS ${exec_headers} ${PROJECT_PUBLIC_HEADERS} ${src}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
endfunction ()
|
||||
@@ -130,8 +144,8 @@ function ( LLVM_COMPILE_CUDA llvm_src headers prefix llvm_bc_cpp_generated extra
|
||||
MAKE_CUDA_BITCODE (${llvm_src} "" llvm_bc "${extra_clang_args}")
|
||||
|
||||
add_custom_command (OUTPUT ${llvm_bc_cpp}
|
||||
COMMAND python "${CMAKE_SOURCE_DIR}/src/liboslexec/serialize-bc.py" ${llvm_bc} ${llvm_bc_cpp} ${prefix}
|
||||
COMMAND ${Python_EXECUTABLE} "${CMAKE_SOURCE_DIR}/src/build-scripts/serialize-bc.py" ${llvm_bc} ${llvm_bc_cpp} ${prefix}
|
||||
MAIN_DEPENDENCY ${llvm_src}
|
||||
DEPENDS "${CMAKE_SOURCE_DIR}/src/liboslexec/serialize-bc.py" ${llvm_src} ${headers} ${llvm_bc}
|
||||
DEPENDS "${CMAKE_SOURCE_DIR}/src/build-scripts/serialize-bc.py" ${llvm_src} ${headers} ${llvm_bc}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
endfunction ()
|
||||
|
||||
@@ -88,7 +88,7 @@ checked_find_package (OpenEXR REQUIRED
|
||||
)
|
||||
# Force Imath includes to be before everything else to ensure that we have
|
||||
# the right Imath/OpenEXR version, not some older version in the system
|
||||
# library. This shoudn't be necessary, except for the common case of people
|
||||
# library. This shouldn't be necessary, except for the common case of people
|
||||
# building against Imath/OpenEXR 3.x when there is still a system-level
|
||||
# install version of 2.x.
|
||||
include_directories(BEFORE ${IMATH_INCLUDES})
|
||||
@@ -105,7 +105,7 @@ endif ()
|
||||
|
||||
# OpenImageIO
|
||||
checked_find_package (OpenImageIO REQUIRED
|
||||
VERSION_MIN 2.2.6
|
||||
VERSION_MIN 2.3.17
|
||||
DEFINITIONS -DOIIO_HIDE_FORMAT=1)
|
||||
|
||||
checked_find_package (pugixml REQUIRED
|
||||
@@ -136,6 +136,14 @@ if (APPLE AND LLVM_VERSION VERSION_EQUAL 10.0.1 AND EXISTS "/usr/local/Cellar/ll
|
||||
" brew upgrade llvm \n"
|
||||
"${ColorReset}\n")
|
||||
endif ()
|
||||
if (LLVM_VERSION VERSION_GREATER_EQUAL 15.0
|
||||
AND ( (CMAKE_COMPILER_IS_APPLECLANG AND APPLECLANG_VERSION_STRING VERSION_LESS 15.0)
|
||||
OR (CMAKE_COMPILER_IS_CLANG AND CLANG_VERSION_STRING VERSION_LESS 15.0)))
|
||||
message (WARNING
|
||||
"${ColorYellow}"
|
||||
"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 ()
|
||||
|
||||
checked_find_package (partio)
|
||||
|
||||
@@ -198,7 +206,7 @@ if (USE_CUDA OR USE_OPTIX)
|
||||
# OptiX setup
|
||||
if (USE_OPTIX)
|
||||
checked_find_package (OptiX REQUIRED
|
||||
VERSION_MIN 5.1)
|
||||
VERSION_MIN 7.0)
|
||||
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")
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
# Copyright Contributors to the Open Shading Language project.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
|
||||
|
||||
function ( EMBED_LLVM_BITCODE_IN_CPP src_list suffix output_name list_to_append_cpp extra_clang_args)
|
||||
|
||||
if (VERBOSE)
|
||||
message (STATUS "EMBED_LLVM_BITCODE_IN_CPP src_list=${src_list}")
|
||||
endif ()
|
||||
|
||||
foreach ( src ${src_list} )
|
||||
get_filename_component ( src_we ${src} NAME_WE )
|
||||
set ( src_asm "${CMAKE_CURRENT_BINARY_DIR}/${src_we}${suffix}.s" )
|
||||
set ( src_bc "${CMAKE_CURRENT_BINARY_DIR}/${src_we}${suffix}.bc" )
|
||||
if (VERBOSE)
|
||||
message (STATUS "EMBED_LLVM_BITCODE_IN_CPP in=${src}")
|
||||
message (STATUS "EMBED_LLVM_BITCODE_IN_CPP asm=${src_asm}")
|
||||
message (STATUS "EMBED_LLVM_BITCODE_IN_CPP bc=${src_bc}")
|
||||
endif ()
|
||||
list ( APPEND src_bc_list ${src_bc} )
|
||||
|
||||
get_property (CURRENT_DEFINITIONS DIRECTORY PROPERTY COMPILE_DEFINITIONS)
|
||||
if (VERBOSE)
|
||||
message (STATUS "Current #defines are ${CURRENT_DEFINITIONS}")
|
||||
endif ()
|
||||
foreach (def ${CURRENT_DEFINITIONS})
|
||||
set (LLVM_COMPILE_FLAGS ${LLVM_COMPILE_FLAGS} "-D${def}")
|
||||
endforeach()
|
||||
set (LLVM_COMPILE_FLAGS ${LLVM_COMPILE_FLAGS} ${SIMD_COMPILE_FLAGS} ${CSTD_FLAGS} ${TOOLCHAIN_FLAGS})
|
||||
# Avoid generating __dso_handle external global
|
||||
set (LLVM_COMPILE_FLAGS ${LLVM_COMPILE_FLAGS} "-fno-use-cxa-atexit")
|
||||
|
||||
# Figure out what program we will use to make the bitcode.
|
||||
if (NOT LLVM_BC_GENERATOR)
|
||||
find_program (LLVM_BC_GENERATOR NAMES "clang++"
|
||||
PATHS "${LLVM_DIRECTORY}/bin" "${LLVM_DIRECTORY}/tools/llvm"
|
||||
NO_CMAKE_PATH NO_DEFAULT_PATH NO_CMAKE_SYSTEM_PATH
|
||||
NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_ENVIRONMENT_PATH)
|
||||
endif ()
|
||||
|
||||
if (NOT LLVM_BC_GENERATOR)
|
||||
message (FATAL_ERROR "You must have a valid llvm bitcode generator (clang++) somewhere.")
|
||||
endif ()
|
||||
if (VERBOSE)
|
||||
message (STATUS "Using LLVM_BC_GENERATOR ${LLVM_BC_GENERATOR} to generate bitcode.")
|
||||
endif()
|
||||
|
||||
if (NOT LLVM_AS_TOOL)
|
||||
find_program (LLVM_AS_TOOL NAMES "llvm-as"
|
||||
PATHS "${LLVM_DIRECTORY}/bin" "${LLVM_DIRECTORY}/tools/llvm"
|
||||
NO_CMAKE_PATH NO_DEFAULT_PATH NO_CMAKE_SYSTEM_PATH
|
||||
NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_ENVIRONMENT_PATH)
|
||||
endif ()
|
||||
|
||||
if (NOT LLVM_LINK_TOOL)
|
||||
find_program (LLVM_LINK_TOOL NAMES "llvm-link"
|
||||
PATHS "${LLVM_DIRECTORY}/bin" "${LLVM_DIRECTORY}/tools/llvm"
|
||||
NO_CMAKE_PATH NO_DEFAULT_PATH NO_CMAKE_SYSTEM_PATH
|
||||
NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_ENVIRONMENT_PATH)
|
||||
endif ()
|
||||
|
||||
|
||||
# Fix specific problem I had on new Apple systems (e.g. Mavericks) with
|
||||
# LLVM/libc++ installed -- for some reason, LLVM 3.4 wasn't finding it,
|
||||
# so in that specific case, append another -I to point it in the right
|
||||
# direction.
|
||||
#if (APPLE AND ${LLVM_BC_GENERATOR} MATCHES ".*clang.*")
|
||||
# exec_program ( "${LLVM_BC_GENERATOR}" ARGS --version OUTPUT_VARIABLE MY_CLANG_VERSION )
|
||||
# string (REGEX REPLACE "clang version ([0-9][.][0-9]+).*" "\\1" MY_CLANG_VERSION "${MY_CLANG_VERSION}")
|
||||
# if ((${MY_CLANG_VERSION} VERSION_GREATER "3.3")
|
||||
# AND (EXISTS "/usr/lib/libc++.dylib")
|
||||
# AND (EXISTS "/Library/Developer/CommandLineTools/usr/lib/c++/v1"))
|
||||
# set (LLVM_COMPILE_FLAGS ${LLVM_COMPILE_FLAGS} "-I/Library/Developer/CommandLineTools/usr/lib/c++/v1")
|
||||
# endif ()
|
||||
#endif ()
|
||||
|
||||
list (TRANSFORM IMATH_INCLUDES PREPEND -I
|
||||
OUTPUT_VARIABLE ALL_IMATH_INCLUDES)
|
||||
list (TRANSFORM OPENEXR_INCLUDES PREPEND -I
|
||||
OUTPUT_VARIABLE ALL_OPENEXR_INCLUDES)
|
||||
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 ()
|
||||
|
||||
# Command to turn the .cpp file into LLVM assembly language .s, into
|
||||
# LLVM bitcode .bc, then back into a C++ file with the bc embedded!
|
||||
add_custom_command ( OUTPUT ${src_bc}
|
||||
COMMAND ${LLVM_BC_GENERATOR}
|
||||
${LLVM_COMPILE_FLAGS}
|
||||
"-I${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"-I${CMAKE_SOURCE_DIR}/src/include"
|
||||
"-I${CMAKE_BINARY_DIR}/include"
|
||||
${ALL_OpenImageIO_INCLUDES}
|
||||
${ALL_IMATH_INCLUDES}
|
||||
#"-isystem ${Boost_INCLUDE_DIRS}" #Does not pick up usr installed boost/thread/tss.hpp for oslexec_pvt.h
|
||||
"-I${Boost_INCLUDE_DIRS}"
|
||||
-DOSL_COMPILING_TO_BITCODE=1
|
||||
-Wno-deprecated-register
|
||||
# the following 2 warnings can be restored when all 3rd parties have fixed their export macros
|
||||
# (dllimport attribute is not supported when compiling for Cuda and triggers a ton of warnings)
|
||||
-Wno-ignored-attributes -Wno-unknown-attributes
|
||||
-O3 -fno-math-errno -S -emit-llvm ${extra_clang_args}
|
||||
-o ${src_asm} ${src}
|
||||
COMMAND ${LLVM_AS_TOOL} -f -o ${src_bc} ${src_asm}
|
||||
# Do NOT setup a MAIN_DEPENDENCY because only 1 may exist
|
||||
# and we may have the several outputs dependent on the same source
|
||||
DEPENDS ${src} ${exec_headers} ${PROJECT_PUBLIC_HEADERS}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
endforeach ()
|
||||
|
||||
|
||||
if (VERBOSE)
|
||||
message ( STATUS "^^^^^^^^^^^^^^^^^^^^^^^^^^" )
|
||||
message ( STATUS "src_bc_list: ${src_bc_list} ")
|
||||
message ( STATUS "^^^^^^^^^^^^^^^^^^^^^^^^^^" )
|
||||
endif()
|
||||
|
||||
# Link all of the individual LLVM bitcode files
|
||||
set ( linked_src_bc "${CMAKE_CURRENT_BINARY_DIR}/${output_name}.bc" )
|
||||
add_custom_command ( OUTPUT ${linked_src_bc}
|
||||
COMMAND ${LLVM_LINK_TOOL} -internalize ${src_bc_list} -o ${linked_src_bc}
|
||||
DEPENDS ${src_bc_list} ${exec_headers} ${PROJECT_PUBLIC_HEADERS} ${src_list}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" )
|
||||
|
||||
# Serialize the linked bitcode into a CPP file
|
||||
set ( src_bc_cpp "${CMAKE_CURRENT_BINARY_DIR}/${output_name}.bc.cpp" )
|
||||
add_custom_command ( OUTPUT ${src_bc_cpp}
|
||||
COMMAND ${Python_EXECUTABLE} "${CMAKE_SOURCE_DIR}/src/build-scripts/serialize-bc.py"
|
||||
${linked_src_bc} ${src_bc_cpp} ${output_name}
|
||||
DEPENDS "${CMAKE_SOURCE_DIR}/src/build-scripts/serialize-bc.py" ${linked_src_bc}
|
||||
${exec_headers} ${PROJECT_PUBLIC_HEADERS}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
|
||||
# add generated .cpp with embedded bitcode to the list of sources
|
||||
set ( ${list_to_append_cpp} ${${list_to_append_cpp}} ${src_bc_cpp} PARENT_SCOPE )
|
||||
|
||||
endfunction ( )
|
||||
@@ -10,7 +10,7 @@
|
||||
# PARTIO_LIBRARIES - library to link against
|
||||
# PARTIO_FOUND - true if Partio was found.
|
||||
|
||||
# Hack! perfer a config if it can be found
|
||||
# Hack! prefer a config if it can be found
|
||||
find_package(partio CONFIG)
|
||||
if (PARTIO_FOUND OR partio_FOUND)
|
||||
if (VERBOSE)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright Contributors to the Open Shading Languge project.
|
||||
# Copyright Contributors to the Open Shading Language project.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ macro (setup_python_module)
|
||||
PRIVATE
|
||||
pybind11::pybind11
|
||||
Python::Python
|
||||
${lib_LIBS} ${SANITIZE_LIBRARIES})
|
||||
${lib_LIBS})
|
||||
if (APPLE)
|
||||
set_target_properties (${target_name} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
|
||||
endif ()
|
||||
|
||||
+75
-23
@@ -1,4 +1,4 @@
|
||||
# Copyright Contributors to the Open Shading Languge project.
|
||||
# Copyright Contributors to the Open Shading Language project.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/
|
||||
|
||||
@@ -16,6 +16,10 @@ add_custom_command (OUTPUT "${CMAKE_BINARY_DIR}/testsuite/runtest.py"
|
||||
MAIN_DEPENDENCY "${CMAKE_SOURCE_DIR}/testsuite/runtest.py")
|
||||
add_custom_target ( CopyFiles ALL DEPENDS "${CMAKE_BINARY_DIR}/testsuite/runtest.py" )
|
||||
|
||||
|
||||
set (OSL_TEST_BIG_TIMEOUT 800 CACHE STRING "Timeout for tests that take a long time")
|
||||
|
||||
|
||||
# add_one_testsuite() - set up one testsuite entry
|
||||
#
|
||||
# Usage:
|
||||
@@ -26,10 +30,12 @@ add_custom_target ( CopyFiles ALL DEPENDS "${CMAKE_BINARY_DIR}/testsuite/runtest
|
||||
# [COMMAND cmd...] - optional override of launch command
|
||||
# )
|
||||
#
|
||||
|
||||
macro (add_one_testsuite testname testsrcdir)
|
||||
cmake_parse_arguments (_tst "" "" "ENV;COMMAND" ${ARGN})
|
||||
set (testsuite "${CMAKE_SOURCE_DIR}/testsuite")
|
||||
set (testdir "${CMAKE_BINARY_DIR}/testsuite/${testname}")
|
||||
file (MAKE_DIRECTORY "${testdir}")
|
||||
if (NOT _tst_COMMAND)
|
||||
set (_tst_COMMAND ${Python_EXECUTABLE} "${testsuite}/runtest.py" ${testdir})
|
||||
if (MSVC_IDE)
|
||||
@@ -45,7 +51,17 @@ macro (add_one_testsuite testname testsrcdir)
|
||||
OSL_TESTSUITE_SRC=${testsrcdir}
|
||||
OSL_TESTSUITE_CUR=${testdir}
|
||||
)
|
||||
file (MAKE_DIRECTORY "${testdir}")
|
||||
|
||||
# We need to suppress the leak sanitizer for "texture" tests, because of a
|
||||
# minor leak inside OIIO (140 bytes! -- inconsequential) but which we
|
||||
# can't use the suppressions list becuase the leaks come from calls made
|
||||
# inside JITed code for which there is not a good stack trace. Any real
|
||||
# leaks from OIIO or its dependencies we assume will be caught by lsan on
|
||||
# the OIIO side, where there is no JIT to complicate things.
|
||||
if (${testname} MATCHES "^texture" OR ${testname} MATCHES "gettextureinfo")
|
||||
list (APPEND _tst_ENV ASAN_OPTIONS=detect_leaks=0:$ENV{ASAN_OPTIONS})
|
||||
endif ()
|
||||
|
||||
add_test ( NAME ${testname} COMMAND ${_tst_COMMAND} )
|
||||
# message ("Test -- env ${_tst_ENV} cmd ${_tst_COMMAND}")
|
||||
set_tests_properties (${testname} PROPERTIES ENVIRONMENT "${_tst_ENV}" )
|
||||
@@ -53,8 +69,7 @@ macro (add_one_testsuite testname testsrcdir)
|
||||
# from piling up together, allocate a few cores each.
|
||||
if (${testname} MATCHES "^render-")
|
||||
set_tests_properties (${testname} PROPERTIES LABELS render
|
||||
TIMEOUT 240
|
||||
PROCESSORS 4 COST 10 TIMEOUT 240)
|
||||
PROCESSORS 4 COST 10 TIMEOUT ${OSL_TEST_BIG_TIMEOUT})
|
||||
endif ()
|
||||
# Some labeling for fun
|
||||
if (${testname} MATCHES "^texture")
|
||||
@@ -76,7 +91,7 @@ macro (add_one_testsuite testname testsrcdir)
|
||||
# These are batched shading regression tests. Some are quite
|
||||
# long, so give them a higher cost and timeout.
|
||||
set_tests_properties (${testname} PROPERTIES LABELS batchregression
|
||||
COST 15 TIMEOUT 300)
|
||||
COST 15 TIMEOUT ${OSL_TEST_BIG_TIMEOUT})
|
||||
endif ()
|
||||
endmacro ()
|
||||
|
||||
@@ -90,6 +105,7 @@ macro ( TESTSUITE )
|
||||
endif ()
|
||||
set (test_all_optix $ENV{TESTSUITE_OPTIX})
|
||||
set (test_all_batched $ENV{TESTSUITE_BATCHED})
|
||||
set (test_all_rs_bitcode $ENV{TESTSUITE_RS_BITCODE})
|
||||
# Add the tests if all is well.
|
||||
set (ALL_TEST_LIST "")
|
||||
set (_testsuite "${CMAKE_SOURCE_DIR}/testsuite")
|
||||
@@ -106,7 +122,7 @@ macro ( TESTSUITE )
|
||||
|
||||
# Run the test unoptimized, unless it matches a few patterns that
|
||||
# we don't test unoptimized (or has an OPTIMIZEONLY marker file).
|
||||
if (NOT _testname MATCHES "optix"
|
||||
if (NOT _testname MATCHES "optix"
|
||||
AND NOT EXISTS "${_testsrcdir}/NOSCALAR"
|
||||
AND NOT EXISTS "${_testsrcdir}/BATCHED_REGRESSION"
|
||||
AND NOT EXISTS "${_testsrcdir}/OPTIMIZEONLY")
|
||||
@@ -123,6 +139,9 @@ 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
|
||||
@@ -141,7 +160,7 @@ macro ( TESTSUITE )
|
||||
add_one_testsuite ("${_testname}.optix.opt" "${_testsrcdir}"
|
||||
ENV TESTSHADE_OPT=2 TESTSHADE_OPTIX=1 )
|
||||
endif ()
|
||||
|
||||
|
||||
if (BUILD_BATCHED)
|
||||
# When building for Batched support, also run it in Batched mode
|
||||
# if there is an BATCHED marker file in the directory.
|
||||
@@ -155,7 +174,7 @@ macro ( TESTSUITE )
|
||||
add_one_testsuite ("${_testname}.batched" "${_testsrcdir}"
|
||||
ENV TESTSHADE_OPT=0 TESTSHADE_BATCHED=1 )
|
||||
endif ()
|
||||
|
||||
|
||||
if ((EXISTS "${_testsrcdir}/BATCHED" OR test_all_batched OR _testname MATCHES "batched")
|
||||
AND NOT EXISTS "${_testsrcdir}/BATCHED_REGRESSION"
|
||||
AND NOT EXISTS "${_testsrcdir}/NOBATCHED"
|
||||
@@ -164,7 +183,7 @@ macro ( TESTSUITE )
|
||||
add_one_testsuite ("${_testname}.batched.opt" "${_testsrcdir}"
|
||||
ENV TESTSHADE_OPT=2 TESTSHADE_BATCHED=1 )
|
||||
endif ()
|
||||
|
||||
|
||||
# When building for Batched support, optionally run a regression test
|
||||
# if there is an BATCHED_REGRESSION marker file in the directory.
|
||||
if ((EXISTS "${_testsrcdir}/BATCHED_REGRESSION")
|
||||
@@ -180,6 +199,25 @@ macro ( TESTSUITE )
|
||||
ENV TESTSHADE_OPT=0 OSL_REGRESSION_TEST=BATCHED )
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# if there is an RS_BITCODE marker file in the directory.
|
||||
if ((EXISTS "${_testsrcdir}/RS_BITCODE" OR test_all_rs_bitcode)
|
||||
AND NOT EXISTS "${_testsrcdir}/BATCHED_REGRESSION"
|
||||
AND NOT EXISTS "${_testsrcdir}/RS_BITCODE_REGRESSION"
|
||||
AND NOT EXISTS "${_testsrcdir}/NOOPTIMIZE")
|
||||
add_one_testsuite ("${_testname}.rsbitcode.opt" "${_testsrcdir}"
|
||||
ENV TESTSHADE_OPT=2 TESTSHADE_RS_BITCODE=1 )
|
||||
endif ()
|
||||
|
||||
# if there is an RS_BITCODE_REGRESSION marker file in the directory.
|
||||
if (EXISTS "${_testsrcdir}/RS_BITCODE_REGRESSION" OR (
|
||||
test_all_rs_bitcode AND EXISTS "${_testsrcdir}/BATCHED_REGRESSION")
|
||||
AND NOT EXISTS "${_testsrcdir}/NOOPTIMIZE")
|
||||
# optimized for right now
|
||||
add_one_testsuite ("${_testname}.regress.rsbitcode.opt" "${_testsrcdir}"
|
||||
ENV TESTSHADE_OPT=2 OSL_REGRESSION_TEST=RS_BITCODE )
|
||||
endif ()
|
||||
|
||||
endforeach ()
|
||||
if (VERBOSE)
|
||||
message (STATUS "Added tests: ${ALL_TEST_LIST}")
|
||||
@@ -191,7 +229,7 @@ macro (osl_add_all_tests)
|
||||
# special installed tests.
|
||||
TESTSUITE ( aastep allowconnect-err andor-reg and-or-not-synonyms
|
||||
arithmetic area-reg arithmetic-reg
|
||||
array array-reg array-copy-reg array-derivs array-range
|
||||
array array-reg array-copy-reg array-derivs array-range
|
||||
array-aassign array-assign-reg array-length-reg
|
||||
bitwise-and-reg bitwise-or-reg bitwise-shl-reg bitwise-shr-reg bitwise-xor-reg
|
||||
blackbody blackbody-reg blendmath breakcont breakcont-reg
|
||||
@@ -200,7 +238,7 @@ macro (osl_add_all_tests)
|
||||
calculatenormal-reg
|
||||
cellnoise closure closure-array color color-reg colorspace comparison
|
||||
complement-reg compile-buffer compassign-reg
|
||||
component-range
|
||||
component-range
|
||||
control-flow-reg connect-components
|
||||
const-array-params const-array-fill
|
||||
debugnan debug-uninit
|
||||
@@ -219,7 +257,9 @@ macro (osl_add_all_tests)
|
||||
globals-needed
|
||||
group-outputs groupstring
|
||||
hash hashnoise hex hyperb
|
||||
ieee_fp ieee_fp-reg if if-reg incdec initlist initops intbits isconnected
|
||||
ieee_fp ieee_fp-reg if if-reg incdec initlist
|
||||
initops initops-instance-clash
|
||||
intbits isconnected
|
||||
isconstant
|
||||
layers layers-Ciassign layers-entry layers-lazy layers-lazyerror
|
||||
layers-nonlazycopy layers-repeatedoutputs
|
||||
@@ -239,7 +279,7 @@ macro (osl_add_all_tests)
|
||||
noise-perlin noise-simplex
|
||||
noise-reg
|
||||
normalize-reg
|
||||
pnoise pnoise-cell pnoise-gabor
|
||||
pnoise pnoise-cell pnoise-gabor
|
||||
pnoise-generic pnoise-perlin
|
||||
pnoise-reg
|
||||
operator-overloading
|
||||
@@ -271,11 +311,20 @@ macro (osl_add_all_tests)
|
||||
raytype raytype-reg raytype-specialized regex-reg reparam
|
||||
render-background render-bumptest
|
||||
render-cornell render-furnace-diffuse
|
||||
render-mx-furnace-burley-diffuse
|
||||
render-mx-furnace-oren-nayar
|
||||
render-mx-furnace-sheen
|
||||
render-mx-burley-diffuse
|
||||
render-mx-dielectric render-mx-dielectric-glass
|
||||
render-mx-conductor
|
||||
render-mx-generalized-schlick render-mx-generalized-schlick-glass
|
||||
render-mx-layer
|
||||
render-mx-sheen
|
||||
render-microfacet render-oren-nayar
|
||||
render-uv render-veachmis render-ward
|
||||
select select-reg shaderglobals shortcircuit
|
||||
smoothstep-reg
|
||||
spline spline-reg splineinverse splineinverse-ident
|
||||
smoothstep-reg
|
||||
spline spline-reg splineinverse splineinverse-ident
|
||||
splineinverse-knots-ascend-reg splineinverse-knots-descend-reg
|
||||
spline-boundarybug spline-derivbug
|
||||
split-reg
|
||||
@@ -299,7 +348,7 @@ macro (osl_add_all_tests)
|
||||
trailing-commas
|
||||
transcendental-reg
|
||||
transitive-assign
|
||||
transform transform-reg transformc transformc-reg trig trig-reg
|
||||
transform transform-reg transformc transformc-reg trig trig-reg
|
||||
typecast
|
||||
unknown-instruction
|
||||
userdata userdata-passthrough
|
||||
@@ -319,10 +368,10 @@ macro (osl_add_all_tests)
|
||||
endif ()
|
||||
|
||||
# Add tests that require the Python bindings if we built them.
|
||||
# We also exclude these tests if this is a sanitizer build on Linux,
|
||||
# because the Python interpreter itself won't be linked with the right asan
|
||||
# We also exclude these tests if this is a sanitizer build, because the
|
||||
# Python interpreter itself won't be linked with the right asan
|
||||
# libraries to run correctly.
|
||||
if (USE_PYTHON AND NOT SANITIZE_ON_LINUX)
|
||||
if (USE_PYTHON AND NOT SANITIZE)
|
||||
TESTSUITE ( python-oslquery )
|
||||
endif ()
|
||||
|
||||
@@ -343,10 +392,13 @@ macro (osl_add_all_tests)
|
||||
TESTSUITE ( testoptix testoptix-noise example-cuda)
|
||||
endif ()
|
||||
|
||||
# Some regression tests have alot of combinations and may need more time to finish
|
||||
# Some regression tests have a lot of combinations and may need more time to finish
|
||||
if (BUILD_BATCHED)
|
||||
set_tests_properties (arithmetic-reg.regress.batched.opt PROPERTIES TIMEOUT 800)
|
||||
set_tests_properties (transform-reg.regress.batched.opt PROPERTIES TIMEOUT 800)
|
||||
set_tests_properties (arithmetic-reg.regress.batched.opt
|
||||
PROPERTIES TIMEOUT ${OSL_TEST_BIG_TIMEOUT})
|
||||
set_tests_properties (transform-reg.regress.batched.opt
|
||||
PROPERTIES TIMEOUT ${OSL_TEST_BIG_TIMEOUT})
|
||||
endif ()
|
||||
|
||||
set_tests_properties (matrix-reg.regress.rsbitcode.opt
|
||||
PROPERTIES TIMEOUT ${OSL_TEST_BIG_TIMEOUT})
|
||||
endmacro()
|
||||
|
||||
+710
-77
@@ -66,7 +66,7 @@ All rights reserved.
|
||||
Editor: Larry Gritz \\
|
||||
\emph{lg@imageworks.com}
|
||||
}
|
||||
\date{{\large Date: 24 Nov 2021 \\
|
||||
\date{{\large Date: 27 Aug 2022 \\
|
||||
% (with corrections, 24 Nov 2021)
|
||||
}
|
||||
\bigskip
|
||||
@@ -1431,7 +1431,7 @@ least 32 bits.
|
||||
|
||||
Integer constants are constructed the same way as in C. The following
|
||||
are examples of {\cf int} constants: {\cf 1}, {\cf -32}, etc. Integer
|
||||
constants may be specified as hexidecimal, for example: {\cf 0x01cf}.
|
||||
constants may be specified as hexadecimal, for example: {\cf 0x01cf}.
|
||||
|
||||
Unlike C, no unsigned, bool, char, short, or long types are supplied.
|
||||
This is to simplify the process of writing shaders (as well as
|
||||
@@ -3778,7 +3778,7 @@ Computes the \emph{inverse} of the {\cf spline()} function, i.e., returns
|
||||
the value $x$ for which \\
|
||||
\spc {\cf spline (basis, x, y...)}\\
|
||||
would return value
|
||||
$v$. Results are undefined if the knots do not specifiy a monotonic
|
||||
$v$. Results are undefined if the knots do not specify a monotonic
|
||||
(only increasing or only decreasing) set of values.
|
||||
|
||||
Note that the combination of {\cf spline} and {\cf splineinverse} makes
|
||||
@@ -3905,7 +3905,7 @@ multi-component types such as \color, the format will be applied to each
|
||||
of the components). The {\cf \%s} expects a {\cf string} or
|
||||
{\cf closure} argument.
|
||||
|
||||
All of the substition commands follow the usual C/C++ formatting rules,
|
||||
All of the substitution commands follow the usual C/C++ formatting rules,
|
||||
so format commands such as {\cf "\%6.2f"}, etc., should work as
|
||||
expected.
|
||||
\apiend
|
||||
@@ -3930,7 +3930,7 @@ and other diagnostic information.
|
||||
\indexapi{fprintf()}
|
||||
The {\cf fprintf()} function works similarly to {\cf printf}, but rather
|
||||
than printing to the default text output stream, the results will be
|
||||
concatentated onto the end of the text file named by {\cf filename}.
|
||||
concatenated onto the end of the text file named by {\cf filename}.
|
||||
\apiend
|
||||
|
||||
\apiitem{string {\ce concat} (string s1, ..., string sN)}
|
||||
@@ -4404,7 +4404,7 @@ will not be modified and {\cf gettextureinfo} will return {\cf 0}.
|
||||
The version of {\cf gettextureinfo} that takes {\cf s} and {\cf t} parameters
|
||||
retrieves information about the texture file that will be used for those
|
||||
texture coordinates. This can be useful for UDIM textures that may use
|
||||
different texture files for different regions, based on the coodinates. For
|
||||
different texture files for different regions, based on the corodinates. For
|
||||
regular, non-UDIM textures, the coordinates, if supplied, will be ignored.
|
||||
When UDIM textures are queried without coordinates supplied, it will succeed
|
||||
and return the texture info only if that parameter is found and has the same
|
||||
@@ -4611,7 +4611,7 @@ Example:
|
||||
\index{material closure functions}
|
||||
\index{functions!closures}
|
||||
|
||||
For \closurecolor functions, the return ``value'' is symbolic and is may
|
||||
For \closurecolor functions, the return ``value'' is symbolic and may
|
||||
be passed to an output variable or assigned to \Ci, to be evaluated at a
|
||||
later time convenient to the renderer in order to compute the exitant
|
||||
radiance in the direction {\cf -I}. But the shader itself cannot
|
||||
@@ -4620,15 +4620,695 @@ examine the numeric values of the \colorclosure.
|
||||
The intent of this specification is to give a minimal but useful set of
|
||||
material closures that you can expect any renderer implementation to
|
||||
provide. Individual renderers may supply additional closures that are
|
||||
specific to the workings of that renderer. Additionally, invidual
|
||||
specific to the workings of that renderer. Additionally, individual
|
||||
renderers may allow additional parameters or controls on the standard
|
||||
closures, passed as token/value pairs following the required arguments
|
||||
(much like the optional arguments to the {\cf texture()} function).
|
||||
Consult the documentation for your specific renderer for details.
|
||||
|
||||
OSL's standard material closures are by synchronized to match the names and
|
||||
properties of the physically-based shading nodes of MaterialX v1.38
|
||||
(\url{https://www.materialx.org/}).
|
||||
|
||||
\subsection{Surface BSDF closures}
|
||||
|
||||
\apiitem{\closurecolor\ {\ce oren_nayar_diffuse_bsdf}(normal N, color albedo, float roughness)}
|
||||
\indexapi{oren_nayar_diffuse_bsdf()}
|
||||
|
||||
Constructs a diffuse reflection BSDF based on the Oren-Nayar reflectance
|
||||
model.
|
||||
|
||||
\noindent Parameters include:
|
||||
|
||||
\apiitem{N}
|
||||
\vspace{12pt}
|
||||
Normal vector of the surface point being shaded.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{albedo}
|
||||
\vspace{12pt}
|
||||
Surface albedo.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{roughness}
|
||||
\vspace{12pt}
|
||||
Surface roughness [0,1]. A value of 0.0 gives Lambertian reflectance.
|
||||
\apiend
|
||||
% \vspace{-16pt}
|
||||
|
||||
% \apiitem{label}
|
||||
% \vspace{12pt}
|
||||
% Optional string parameter to name this component. For use in AOVs / LPEs.
|
||||
% \apiend
|
||||
|
||||
The Oren-Nayar reflection model is described in M.\ Oren and S.\ K.\
|
||||
Nayar, ``Generalization of Lambert's Reflectance Model,'' Proceedings of
|
||||
SIGGRAPH 1994, pp.239-246 (July, 1994).
|
||||
|
||||
\apiend
|
||||
|
||||
|
||||
\subsection{Surface material closures}
|
||||
\apiitem{\colorclosure\ {\ce burley_diffuse_bsdf} (normal N, color albedo, float roughness)}
|
||||
\indexapi{burley_diffuse_bsdf()}
|
||||
|
||||
Constructs a diffuse reflection BSDF based on the corresponding component of
|
||||
the Disney Principled shading model.
|
||||
|
||||
\noindent Parameters include:
|
||||
|
||||
\apiitem{N}
|
||||
\vspace{12pt}
|
||||
Normal vector of the surface point being shaded.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{albedo}
|
||||
\vspace{12pt}
|
||||
Surface albedo.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{roughness}
|
||||
\vspace{12pt}
|
||||
Surface roughness [0,1]. A value of 0.0 gives Lambertian reflectance.
|
||||
\apiend
|
||||
% \vspace{-16pt}
|
||||
|
||||
% \apiitem{label}
|
||||
% \vspace{12pt}
|
||||
% Optional string parameter to name this component. For use in AOVs / LPEs.
|
||||
% \apiend
|
||||
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce dielectric_bsdf} (normal N, vector U, color reflection_tint, \\
|
||||
\spc\spc color transmission_tint, float roughness_x, float roughness_y, \\
|
||||
\spc\spc float ior, string distribution)}
|
||||
\indexapi{dielectric_bsdf()}
|
||||
|
||||
Constructs a reflection and/or transmission BSDF based on a microfacet
|
||||
reflectance model and a Fresnel curve for dielectrics. The two tint parameters
|
||||
control the contribution of each reflection/transmission lobe. The tints
|
||||
should remain 100\% white for a physically correct dielectric, but can be
|
||||
tweaked for artistic control or set to 0.0 for disabling a lobe.
|
||||
|
||||
The closure may be vertically layered over a base BSDF for the surface beneath
|
||||
the dielectric layer. This is done using the {\cf layer()} closure. By
|
||||
chaining multiple {\cf dielectric_bsdf} closures you can describe a surface
|
||||
with multiple specular lobes. If transmission is enabled (transmission_tint
|
||||
$>$ 0.0) the closure may be layered over a VDF closure describing the surface
|
||||
interior to handle absorption and scattering inside the medium.
|
||||
|
||||
\noindent Parameters include:
|
||||
|
||||
\apiitem{N}
|
||||
\vspace{12pt}
|
||||
Normal vector of the surface point being shaded.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{U}
|
||||
\vspace{12pt}
|
||||
Tangent vector of the surface point being shaded.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{reflection_tint}
|
||||
\vspace{12pt}
|
||||
Weight per color channel for the reflection lobe. Should be (1,1,1) for a physically-correct dielectric surface, but can be tweaked for artistic control. Set to (0,0,0) to disable reflection.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{transmission_tint}
|
||||
\vspace{12pt}
|
||||
Weight per color channel for the transmission lobe. Should be (1,1,1) for a physically-correct dielectric surface, but can be tweaked for artistic control. Set to (0,0,0) to disable transmission.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{roughness_x}
|
||||
\vspace{12pt}
|
||||
Surface roughness in the U direction with a perceptually linear response over its range.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{roughness_y}
|
||||
\vspace{12pt}
|
||||
Surface roughness in the V direction with a perceptually linear response
|
||||
over its range.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{ior}
|
||||
\vspace{12pt}
|
||||
Refraction index.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{distribution}
|
||||
\vspace{12pt}
|
||||
Microfacet distribution. An implementation is expected to support the
|
||||
following distributions: \qkw{ggx}
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{thinfilm_thickness}
|
||||
\vspace{12pt}
|
||||
Optional float parameter for thickness of an iridescent thin film layer on
|
||||
top of this BSDF. Given in nanometers.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{thinfilm_ior}
|
||||
\vspace{12pt}
|
||||
Optional float parameter for refraction index of the thin film layer.
|
||||
\apiend
|
||||
% \vspace{-16pt}
|
||||
|
||||
% \apiitem{label}
|
||||
% \vspace{12pt}
|
||||
% Optional string parameter to name this component. For use in AOVs / LPEs.
|
||||
% \apiend
|
||||
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce conductor_bsdf} (normal N, vector U, float roughness_x, \\
|
||||
\spc\spc float roughness_y, color ior, color extinction, string distribution)}
|
||||
\indexapi{conductor_bsdf()}
|
||||
|
||||
Constructs a reflection BSDF based on a microfacet reflectance model. Uses a
|
||||
Fresnel curve with complex refraction index for conductors/metals. If an
|
||||
artistic parametrization is preferred the {\cf artistic_ior()} utility
|
||||
function can be used to convert from artistic to physical parameters.
|
||||
|
||||
\noindent Parameters include:
|
||||
|
||||
\apiitem{N}
|
||||
\vspace{12pt}
|
||||
Normal vector of the surface point being shaded.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{U}
|
||||
\vspace{12pt}
|
||||
Tangent vector of the surface point being shaded.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{roughness_x}
|
||||
\vspace{12pt}
|
||||
Surface roughness in the U direction with a perceptually linear response over its range.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{roughness_y}
|
||||
\vspace{12pt}
|
||||
Surface roughness in the V direction with a perceptually linear response over its range.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{ior}
|
||||
\vspace{12pt}
|
||||
Refraction index.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{extinction}
|
||||
\vspace{12pt}
|
||||
Extinction coefficient.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{distribution}
|
||||
\vspace{12pt}
|
||||
Microfacet distribution. An implementation is expected to support the
|
||||
following distributions: \qkw{ggx}
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{thinfilm_thickness}
|
||||
\vspace{12pt}
|
||||
Optional float parameter for thickness of an iridescent thin film layer on
|
||||
top of this BSDF. Given in nanometers.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{thinfilm_ior}
|
||||
\vspace{12pt}
|
||||
Optional float parameter for refraction index of the thin film layer.
|
||||
\apiend
|
||||
% \vspace{-16pt}
|
||||
|
||||
% \apiitem{label}
|
||||
% \vspace{12pt}
|
||||
% Optional string parameter to name this component. For use in AOVs / LPEs.
|
||||
% \apiend
|
||||
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce generalized_schlick_bsdf} (normal N, vector U, \\
|
||||
\spc\spc color reflection_tint, color transmission_tint, \\
|
||||
\spc\spc float roughness_x, float roughness_y, color f0, color f90, \\
|
||||
\spc\spc float exponent, string distribution)}
|
||||
\indexapi{generalized_schlick_bsdf()}
|
||||
|
||||
Constructs a reflection and/or transmission BSDF based on a microfacet
|
||||
reflectance model and a generalized Schlick Fresnel curve. The two tint
|
||||
parameters control the contribution of each reflection/transmission lobe.
|
||||
|
||||
The closure may be vertically layered over a base BSDF for the surface beneath
|
||||
the dielectric layer. This is done using the layer() closure. By chaining
|
||||
multiple {\cf dielectric_bsdf} closures you can describe a surface with multiple
|
||||
specular lobes. If transmission is enabled (transmission_tint $>$ 0.0) the
|
||||
closure may be layered over a VDF closure describing the surface interior to
|
||||
handle absorption and scattering inside the medium.
|
||||
|
||||
\noindent Parameters include:
|
||||
|
||||
\apiitem{N}
|
||||
\vspace{12pt}
|
||||
Normal vector of the surface point being shaded.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{U}
|
||||
\vspace{12pt}
|
||||
Tangent vector of the surface point being shaded.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{reflection_tint}
|
||||
\vspace{12pt}
|
||||
Weight per color channel for the reflection lobe. Set to (0,0,0) to disable
|
||||
reflection.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{transmission_tint}
|
||||
\vspace{12pt}
|
||||
Weight per color channel for the transmission lobe. Set to (0,0,0) to
|
||||
disable transmission.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{roughness_x}
|
||||
\vspace{12pt}
|
||||
Surface roughness in the U direction with a perceptually linear response
|
||||
over its range.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{roughness_y}
|
||||
\vspace{12pt}
|
||||
Surface roughness in the V direction with a perceptually linear response
|
||||
over its range.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{f0}
|
||||
\vspace{12pt}
|
||||
Reflectivity per color channel at facing angles.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{f90}
|
||||
\vspace{12pt}
|
||||
Reflectivity per color channel at grazing angles.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{exponent}
|
||||
\vspace{12pt}
|
||||
Variable exponent for the Schlick Fresnel curve, the default value should be
|
||||
5.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{distribution}
|
||||
\vspace{12pt}
|
||||
Microfacet distribution. An implementation is expected to support the
|
||||
following distributions: \qkw{ggx}
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{thinfilm_thickness}
|
||||
\vspace{12pt}
|
||||
Optional float parameter for thickness of an iridescent thin film layer on
|
||||
top of this BSDF. Given in nanometers.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{thinfilm_ior}
|
||||
\vspace{12pt}
|
||||
Optional float parameter for refraction index of the thin film layer.
|
||||
\apiend
|
||||
% \vspace{-16pt}
|
||||
|
||||
% \apiitem{label}
|
||||
% \vspace{12pt}
|
||||
% Optional string parameter to name this component. For use in AOVs / LPEs.
|
||||
% \apiend
|
||||
|
||||
\apiend
|
||||
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce translucent_bsdf} (normal N, color albedo)}
|
||||
\indexapi{translucent_bsdf()}
|
||||
|
||||
Constructs a translucent (diffuse transmission) BSDF based on the Lambert
|
||||
reflectance model.
|
||||
|
||||
\noindent Parameters include:
|
||||
|
||||
\apiitem{N}
|
||||
\vspace{12pt}
|
||||
Normal vector of the surface point being shaded.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{albedo}
|
||||
\vspace{12pt}
|
||||
Surface albedo.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{roughness}
|
||||
\vspace{12pt}
|
||||
Surface roughness [0,1]. A value of 0.0 gives Lambertian reflectance.
|
||||
\apiend
|
||||
% \vspace{-16pt}
|
||||
|
||||
% \apiitem{label}
|
||||
% \vspace{12pt}
|
||||
% Optional string parameter to name this component. For use in AOVs / LPEs.
|
||||
% \apiend
|
||||
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce transparent_bsdf} ( )}
|
||||
\indexapi{transparent_bsdf()}
|
||||
|
||||
Constructs a closure that represents straight transmission through a surface.
|
||||
|
||||
\apiend
|
||||
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce subsurface_bssrdf} ( )}
|
||||
\indexapi{subsurface_bssrdf}
|
||||
Constructs a BSSRDF for subsurface scattering within a homogeneous medium.
|
||||
|
||||
\noindent Parameters include:
|
||||
|
||||
\apiitem{N}
|
||||
\vspace{12pt}
|
||||
Normal vector of the surface point being shaded.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{albedo}
|
||||
\vspace{12pt}
|
||||
Single-scattering albedo of the medium.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{transmission_depth}
|
||||
\vspace{12pt}
|
||||
Distance travelled inside the medium by white light before its color becomes
|
||||
transmission_color by Beer's law. Given in scene length units, range
|
||||
[0,infinity). Together with transmission_color this determines the
|
||||
extinction coefficient of the medium.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{transmission_color}
|
||||
\vspace{12pt}
|
||||
Desired color resulting from white light transmitted a distance of
|
||||
'transmission_depth' through the medium. Together with transmission_depth
|
||||
this determines the extinction coefficient of the medium.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{anisotropy}
|
||||
\vspace{12pt}
|
||||
Scattering anisotropy [-1,1]. Negative values give backwards scattering,
|
||||
positive values give forward scattering, and 0.0 gives uniform scattering.
|
||||
\apiend
|
||||
|
||||
% \vspace{-16pt}
|
||||
|
||||
% \apiitem{label}
|
||||
% \vspace{12pt}
|
||||
% Optional string parameter to name this component. For use in AOVs / LPEs.
|
||||
% \apiend
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce sheen_bsdf} (normal N, color albedo, float roughness)}
|
||||
\indexapi{sheen_bsdf()}
|
||||
|
||||
Constructs a microfacet BSDF for the back-scattering properties of cloth-like
|
||||
materials. This closure may be vertically layered over a base BSDF, where
|
||||
energy that is not reflected will be transmitted to the base closure.
|
||||
|
||||
\noindent Parameters include:
|
||||
|
||||
\apiitem{N}
|
||||
\vspace{12pt}
|
||||
Normal vector of the surface point being shaded.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{albedo}
|
||||
\vspace{12pt}
|
||||
Surface albedo.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{roughness}
|
||||
\vspace{12pt}
|
||||
Surface roughness [0,1].
|
||||
\apiend
|
||||
% \vspace{-16pt}
|
||||
|
||||
% \apiitem{label}
|
||||
% \vspace{12pt}
|
||||
% Optional string parameter to name this component. For use in AOVs / LPEs.
|
||||
% \apiend
|
||||
|
||||
\apiend
|
||||
|
||||
|
||||
|
||||
\subsection{Volumetric material closures}
|
||||
|
||||
\apiitem{\colorclosure\ {\ce anisotropic_vdf} (color albedo, color extinction, float anisotropy)}
|
||||
\indexapi{anisotropic_vdf}
|
||||
|
||||
Constructs a VDF scattering light for a general participating medium, based on
|
||||
the Henyey-Greenstein phase function. Forward, backward and uniform scattering
|
||||
is supported and controlled by the anisotropy input.
|
||||
|
||||
\noindent Parameters include:
|
||||
|
||||
\apiitem{albedo}
|
||||
\vspace{12pt}
|
||||
Single-scattering albedo of the medium.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{extinction}
|
||||
\vspace{12pt}
|
||||
Volume extinction coefficient.
|
||||
\apiend
|
||||
|
||||
\apiitem{anisotropy}
|
||||
\vspace{12pt}
|
||||
Scattering anisotropy [-1,1]. Negative values give backwards scattering,
|
||||
positive values give forward scattering, and 0.0 gives uniform scattering.
|
||||
\apiend
|
||||
|
||||
% \vspace{-16pt}
|
||||
|
||||
% \apiitem{label}
|
||||
% \vspace{12pt}
|
||||
% Optional string parameter to name this component. For use in AOVs / LPEs.
|
||||
% \apiend
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce medium_vdf} (color albedo, float transmission_depth, \\
|
||||
\spc\spc color transmission_color, float anisotropy, float ior, int priority)}
|
||||
\indexapi{medium_vdf}
|
||||
|
||||
Constructs a VDF for light passing through a dielectric homogeneous medium,
|
||||
such as glass or liquids. The parameters {\cf transmission_depth} and
|
||||
{\cf transmission_color} control the extinction coefficient of the medium in an
|
||||
artist-friendly way. A priority can be set to determine the ordering of
|
||||
overlapping media.
|
||||
|
||||
\noindent Parameters include:
|
||||
|
||||
\apiitem{albedo}
|
||||
\vspace{12pt}
|
||||
Single-scattering albedo of the medium.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{transmission_depth}
|
||||
\vspace{12pt}
|
||||
Distance travelled inside the medium by white light before its color becomes
|
||||
transmission_color by Beer's law. Given in scene length units, range
|
||||
[0,infinity). Together with transmission_color this determines the
|
||||
extinction coefficient of the medium.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{transmission_color}
|
||||
\vspace{12pt}
|
||||
Desired color resulting from white light transmitted a distance of
|
||||
'transmission_depth' through the medium. Together with transmission_depth
|
||||
this determines the extinction coefficient of the medium.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{anisotropy}
|
||||
\vspace{12pt}
|
||||
Scattering anisotropy [-1,1]. Negative values give backwards scattering,
|
||||
positive values give forward scattering, and 0.0 gives uniform scattering.
|
||||
\apiend
|
||||
|
||||
\apiitem{ior}
|
||||
\vspace{12pt}
|
||||
Refraction index of the medium.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{priority}
|
||||
\vspace{12pt}
|
||||
Priority of this medium (for nested dielectrics).
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
% \vspace{-16pt}
|
||||
|
||||
% \apiitem{label}
|
||||
% \vspace{12pt}
|
||||
% Optional string parameter to name this component. For use in AOVs / LPEs.
|
||||
% \apiend
|
||||
\apiend
|
||||
|
||||
|
||||
\subsection{Light emission closures}
|
||||
|
||||
\apiitem{\colorclosure\ {\ce uniform_edf} (color emittance)}
|
||||
\indexapi{uniform_edf}
|
||||
Constructs an EDF emitting light uniformly in all directions.
|
||||
This is used to represent a glowing/emissive material.
|
||||
When called in the context of a surface shader group, it implies that
|
||||
light is emitted in a full hemisphere centered around the surface
|
||||
normal. When called in the context of a volume shader group, it implies
|
||||
that light is emitted evenly in all directions around the point being
|
||||
shaded.
|
||||
|
||||
The {\cf emittance} parameter is the amount of emission and
|
||||
has units of radiance (e.g.,
|
||||
$\mathrm{W}\cdot\mathrm{sr}^{-1}\cdot\mathrm{m}^{-2}$). This means that a surface
|
||||
directly seen by the camera will directly reproduce the closure weight in the
|
||||
final pixel, regardless of being a surface or a volume.
|
||||
|
||||
For an emissive surface, if you divide the return value of {\cf uniform_edf()} by
|
||||
{\cf surfacearea() * M_PI}, then you can easily specify the total emissive
|
||||
power of the light (e.g., $\mathrm{W}$), regardless of its physical size.
|
||||
\apiend
|
||||
|
||||
|
||||
\subsection{Layering and Signaling closures}
|
||||
|
||||
\apiitem{\colorclosure\ {\ce layer} (closure color top, closure color base)}
|
||||
\indexapi{layer()}
|
||||
Vertically layer a layerable BSDF such as {\cf dielectric_bsdf},
|
||||
{\cf generalized_schlick_bsdf} or {\cf sheen_bsdf} over a BSDF or VDF. The
|
||||
implementation is target specific, but a standard way of handling this is by
|
||||
albedo scaling, using {\cf base*(1-reflectance(top)) + top}, where
|
||||
reflectance() calculates the directional albedo of a given top BSDF.
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce holdout} ( )}
|
||||
\indexapi{holdout()}
|
||||
Returns a \colorclosure that does not represent any additional light
|
||||
reflection from the surface, but does signal to the renderer that
|
||||
the surface is a \emph{holdout object} (appears transparent in
|
||||
the final output yet hides objects behind it). ``Partial holdouts''
|
||||
may be designated by weighting the {\cf holdout()} closure by a
|
||||
weight that is less than 1.0.
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce debug} (string outputname)}
|
||||
\indexapi{debug()}
|
||||
Returns a \colorclosure that does not represent any additional light
|
||||
reflection from the surface, but does signal to the renderer to add
|
||||
the weight of the closure (which may be a {\cf float} or a \color)
|
||||
to the named output (i.e., AOV).
|
||||
\apiend
|
||||
|
||||
|
||||
\subsection{Material utility functions}
|
||||
|
||||
\apiitem{void {\ce artistic_ior} (color reflectivity, color edge_tint, \\
|
||||
\spc\spc output color ior, output color extinction)}
|
||||
\indexapi{artistic_ior()}
|
||||
Converts the artistic parameterization reflectivity and edge_tint to complex IOR values.
|
||||
To be used with the conductor_bsdf() closure.
|
||||
|
||||
\noindent Parameters include:
|
||||
|
||||
\apiitem{reflectivity}
|
||||
\vspace{12pt}
|
||||
Reflectivity per color channel at facing angles (\emph{r} parameter in [OG14])
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{edge_tint}
|
||||
\vspace{12pt}
|
||||
Color bias for grazing angles (\emph{g} parameter in [OG14]).
|
||||
NOTE: This is not equal to 'f90' in a Schlick Fresnel parameterization.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{ior}
|
||||
\vspace{12pt}
|
||||
Output refraction index.
|
||||
\apiend
|
||||
\vspace{-16pt}
|
||||
|
||||
\apiitem{extinction}
|
||||
\vspace{12pt}
|
||||
Output extinction coefficient.
|
||||
\apiend
|
||||
% \vspace{-16pt}
|
||||
|
||||
Reference: [OG14] Ole Gulbrandsen, "Artist Friendly Metallic Fresnel", Journal
|
||||
of Computer Graphics Tools 3(4), 2014.
|
||||
\url{http://jcgt.org/published/0003/04/03/paper.pdf}
|
||||
\apiend
|
||||
|
||||
|
||||
\subsection{Deprecated closures}
|
||||
|
||||
These were described in the original OSL language specification, but
|
||||
beginning with OSL 1.12, these are considered deprecated. Support for
|
||||
them will be removed entirely in OSL 2.0.
|
||||
|
||||
\subsubsection{Deprecated Surface closures}
|
||||
|
||||
\apiitem{\colorclosure\ {\ce diffuse} (normal N)}
|
||||
\indexapi{diffuse()}
|
||||
@@ -4664,7 +5344,7 @@ Nayar, ``Generalization of Lambert's Reflectance Model,'' Proceedings of
|
||||
SIGGRAPH 1994, pp.239-246 (July, 1994).
|
||||
|
||||
\begin{comment}
|
||||
Like all \closurecolors, the return ``value'' is symbolic and is may be
|
||||
Like all \closurecolors, the return ``value'' is symbolic and may be
|
||||
evaluated at a later time convenient to the renderer in order to compute
|
||||
the exitant radiance in the direction {\cf -I}. But aside from the
|
||||
fact that the shader cannot examine the numeric values of the
|
||||
@@ -4745,33 +5425,6 @@ implemented as follows:
|
||||
\end{comment}
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce microfacet} (string distribution, normal N, vector
|
||||
U, \\ \bigspc\bigspc float xalpha, float yalpha, float eta, int refract)}
|
||||
\indexapi{microfacet()}
|
||||
|
||||
Returns a \colorclosure that represents scattering on the
|
||||
surface using some microfacet distribution such as \qkw{beckmann} or \qkw{ggx} (as
|
||||
described in Walter et al., ``Microfacet Models for Refraction through Rough
|
||||
Surfaces,'' Eurographics Symposium on Rendering, 2007).
|
||||
Both {\cf xalpha} and {\cf yalpha} control how rough the microstructure of the
|
||||
surface is, possibly in an anisotropic way if they are different. In the
|
||||
anisotropic case {\cf U} must be a vector orthogonal to {\cf N} to specify the
|
||||
direction. These values are expected to be the alpha values of the distribution
|
||||
as it appears in the literature, not a universal roughness measure.
|
||||
The {\cf eta} parameter is the index of refraction of the material, and
|
||||
{\cf refract} is a enumeration flag that controls if the BSDF is reflective ({\cf 0}),
|
||||
refractive ({\cf 1}) or both at once ({\cf 2}). The implementation must not rely on
|
||||
{\cf U} when the roughness is isotropic or the given vector is zero.
|
||||
|
||||
The list of supported distributions will change from renderer to renderer, and
|
||||
also the behavior when an unsupported distribution is requested. It is up to the
|
||||
implementation to issue an error or to default to a supported one. Also it is
|
||||
expected that the alias \qkw{default} must work as a distribution in any renderer.
|
||||
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce microfacet} (string distribution, normal N,
|
||||
\\ \bigspc\bigspc float alpha, float eta, int refract)}
|
||||
\indexapi{microfacet()}
|
||||
@@ -4823,7 +5476,6 @@ implemented as follows:
|
||||
\end{code}
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce transparent} ( )}
|
||||
\indexapi{transparent()}
|
||||
|
||||
@@ -4867,8 +5519,7 @@ scattering} exhibited by the surface.
|
||||
\apiend
|
||||
\end{comment}
|
||||
|
||||
|
||||
\subsection{Volumetric material closures}
|
||||
\subsubsection{Deprecated Volumetric closures}
|
||||
|
||||
\apiitem{\colorclosure\ {\ce isotropic} ( )}
|
||||
\indexapi{isotropic}
|
||||
@@ -4877,18 +5528,16 @@ volumetric material, scattering light evenly in all directions,
|
||||
regardless of its original direction.
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce henyey_greenstein} (float g)}
|
||||
\indexapi{henyey_greenstein}
|
||||
Returns a \colorclosure that represents the directional volumetric
|
||||
scattering by small suspended particles. The {\cf g} parameter is the
|
||||
anisotropy factor, ranging from $-1$ to $1$), with positive values
|
||||
anisotropy factor, in the range $(-1, 1)$, with positive values
|
||||
indicating predominantly forward-scattering, negative values indicating
|
||||
predominantly back-scattering, and value of $g=0$ resulting in isotropic
|
||||
scattering.
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce absorption} ( )}
|
||||
\indexapi{absorption}
|
||||
Returns a \colorclosure that does not represent any additional
|
||||
@@ -4898,8 +5547,7 @@ volumetric material, scattering light evenly in all directions,
|
||||
regardless of its original direction.
|
||||
\apiend
|
||||
|
||||
|
||||
\subsection{Light emission closures}
|
||||
\subsubsection{Deprecated Emission closures}
|
||||
|
||||
\apiitem{\colorclosure\ {\ce emission} ( )}
|
||||
\indexapi{emission}
|
||||
@@ -4915,7 +5563,7 @@ $\mathrm{W}\cdot\mathrm{sr}^{-1}\cdot\mathrm{m}^{-2}$). This means that a surfac
|
||||
directly seen by the camera will directly reproduce the closure weight in the
|
||||
final pixel, regardless of being a surface or a volume.
|
||||
|
||||
For surface emission, If you divide {\cf emission()} by
|
||||
For an emissive surface, if you divide the return value of {\cf emission()} by
|
||||
{\cf surfacearea() * M_PI}, then you can easily specify the total emissive
|
||||
power of the light (e.g., $\mathrm{W}$), regardless of its physical size.
|
||||
\apiend
|
||||
@@ -4930,30 +5578,6 @@ up from an HDRI environment map.
|
||||
\apiend
|
||||
|
||||
|
||||
\subsection{Signaling closures}
|
||||
|
||||
\apiitem{\colorclosure\ {\ce holdout} ( )}
|
||||
\indexapi{holdout()}
|
||||
Returns a \colorclosure that does not represent any additional light
|
||||
reflection from the surface, but does signal to the renderer that
|
||||
the surface is a \emph{holdout object} (appears transparent in
|
||||
the final output yet hides objects behind it). ``Partial holdouts''
|
||||
may be designated by weighting the {\cf holdout()} closure by a
|
||||
weight that is less than 1.0.
|
||||
\apiend
|
||||
|
||||
|
||||
\apiitem{\colorclosure\ {\ce debug} (string outputname)}
|
||||
\indexapi{debug()}
|
||||
Returns a \colorclosure that does not represent any additional light
|
||||
reflection from the surface, but does signal to the renderer to add
|
||||
the weight of the closure (which may be a {\cf float} or a \color)
|
||||
to the named output (i.e., AOV).
|
||||
\apiend
|
||||
|
||||
|
||||
|
||||
|
||||
\newpage
|
||||
\section{Renderer state and message passing}
|
||||
\label{sec:stdlib:state}
|
||||
@@ -5750,7 +6374,7 @@ programming language design)?
|
||||
|
||||
This spec is written assuming that \color should explicitly be
|
||||
3-component RGB. Alternately, we could add global \inttype\ {\cf ncomps} that gives the
|
||||
numer of components in a \color, and eliminate any built-in operations
|
||||
number of components in a \color, and eliminate any built-in operations
|
||||
and library functions that seem to require or imply a 3-component color
|
||||
model (including type casting between \color and the 3-component
|
||||
\point-like types).
|
||||
@@ -5862,7 +6486,7 @@ anybody want to argue for any of the following to be included?
|
||||
|
||||
We have defined structures as being allowed to consist only of basic
|
||||
types and arrays thereof --- not structures of structures. This
|
||||
restriction makes for a simpler grammar and implementation, simplier
|
||||
restriction makes for a simpler grammar and implementation, simpler
|
||||
renderer-side APIs for passing data to shaders, and simpler APIs for
|
||||
libraries that query parameters of compiled shaders. But if people
|
||||
strongly feel like structures-of-structures is an important feature, we
|
||||
@@ -5948,7 +6572,7 @@ about it.
|
||||
|
||||
\subsection{Nomenclature}
|
||||
|
||||
Does anybody have a perference for \dPdu and \dPdv (borrowing the
|
||||
Does anybody have a preference for \dPdu and \dPdv (borrowing the
|
||||
RenderMan names, but awkward for primitives without a consistent $u,v$
|
||||
parameterization?), versus something more generic such as {\cf T} and
|
||||
{\cf B} (tangent and bitangent, without explicitly saying how they are
|
||||
@@ -6134,6 +6758,9 @@ full control in the shader.
|
||||
may be shared among multiple geometric primitives. Also sometimes
|
||||
called \emph{graphics state}.
|
||||
|
||||
\item[BSDF.] Bidirectional scattering distribution function, a
|
||||
function that describes light scattering properties of a surface.
|
||||
|
||||
\item[Built-in function.] A function callable from within a shader, where
|
||||
the implementation of the function is provided by the renderer (as
|
||||
opposed to a function that the shader author writes in \langname
|
||||
@@ -6144,7 +6771,7 @@ full control in the shader.
|
||||
at a later time to yield a final numeric value.
|
||||
|
||||
\item[Connection.] A routing of the value of an \emph{output parameter}
|
||||
of one \emph{shader layer} to an \emph{input paramter} of another
|
||||
of one \emph{shader layer} to an \emph{input parameter} of another
|
||||
shader layer within the same \emph{shader group}.
|
||||
|
||||
\item[Default parameter value.] The initial value of a \emph{shader
|
||||
@@ -6155,6 +6782,9 @@ full control in the shader.
|
||||
is explicitly given in the code for that shader, and may either be
|
||||
a constant or a computed expression.
|
||||
|
||||
\item[EDF.] Emission distribution function, a function that describes
|
||||
the distribution of light emitted by a light source.
|
||||
|
||||
\item[Geometric primitive.] A single shape, such as a NURBS patch, a
|
||||
polygon or subdivision mesh, a hair primitive, etc.
|
||||
|
||||
@@ -6190,7 +6820,7 @@ full control in the shader.
|
||||
|
||||
\item[Primitive variable.] A named variable, and values, attached to an
|
||||
individual geometric primitive. Primitive variables may have one of
|
||||
serveral \emph{interpolation methods} --- such as a single value for
|
||||
several \emph{interpolation methods} --- such as a single value for
|
||||
the whole primitive, a value for each piece or face of the primitive,
|
||||
or per-vertex values that are smoothly interpolated across the
|
||||
surface.
|
||||
@@ -6199,12 +6829,12 @@ full control in the shader.
|
||||
that is visible and directly callable by the renderer, as opposed to
|
||||
merely being called from other code within the shader. Public methods
|
||||
must be \emph{top-level} (not defined within other functions) and must
|
||||
be preceeded by the {\cf public} keyword.
|
||||
be preceded by the {\cf public} keyword.
|
||||
|
||||
\item[Shader.] A small self-contained program written in \langname, used
|
||||
to extend the functionality of a renderer with custom behavior of
|
||||
materials and lights. A particular shader may have multiple
|
||||
\emph{shader instances} within a scene, each of which has ts unique
|
||||
\emph{shader instances} within a scene, each of which has its unique
|
||||
\emph{instance parameters}, transformation, etc.
|
||||
|
||||
\item[Shader function.] A function written in \langname that may be
|
||||
@@ -6239,6 +6869,9 @@ full control in the shader.
|
||||
\item[Shading.] The computations within a renderer that implement the
|
||||
behavior and visual appearance of materials and lights.
|
||||
|
||||
\item[VDF.] Volumetric distribution function, a function that describes
|
||||
the scattering properties of a volume.
|
||||
|
||||
\end{description}
|
||||
|
||||
\end{appendix}
|
||||
|
||||
Binary file not shown.
@@ -11,7 +11,7 @@
|
||||
_testshade_ basics
|
||||
==================================================
|
||||
|
||||
The OSL software distribution inculdes `testshade`, a command-line utility
|
||||
The OSL software distribution includes `testshade`, a command-line utility
|
||||
that was written for OSL unit tests, and for a "test harness" in which we
|
||||
can execute shaders for debugging (the shaders or OSL itself) in isolation
|
||||
from any particular rendering system.
|
||||
@@ -28,7 +28,7 @@ itself, it has a number of potential uses in a production studio, including:
|
||||
* Baking procedural patterns into textures.
|
||||
|
||||
* Benchmarking shaders and evaluating their performance, including
|
||||
comparitive tests such as "is it faster to code it this way or that way?"
|
||||
comparative tests such as "is it faster to code it this way or that way?"
|
||||
|
||||
* Exploring the inner workings of OSL's runtime optimizer, to answer
|
||||
questions like: "will this idiom optimize away at runtime when I use
|
||||
@@ -176,7 +176,7 @@ Helpful command line arguments:
|
||||
|
||||
For the sake of simplicity, this document presents almost all examples as if
|
||||
they consisted of just a single shader node. But `testshade` is able to
|
||||
specify and execut entire shader groups (networks of shader nodes). The
|
||||
specify and execute entire shader groups (networks of shader nodes). The
|
||||
remainder of this section will explain how this can be done.
|
||||
|
||||
Let's make a simple shader network as an example.
|
||||
@@ -582,7 +582,7 @@ single texture lookup.
|
||||
|
||||
|
||||
|
||||
## Controling optimization
|
||||
## Controlling optimization
|
||||
|
||||
You can control the optimization level overall:
|
||||
|
||||
@@ -638,7 +638,7 @@ that they are not optimized away so as to lead you to an inaccurate
|
||||
reflection of what optimizations would really happen at render time. At the
|
||||
same time, be careful not to inadvertently set `lockgeom=0` for parameters
|
||||
that will typically be set to default values, instance values, or
|
||||
connections from layers that are likely to be analized and found to emit
|
||||
connections from layers that are likely to be analyzed and found to emit
|
||||
constants for theor outputs -- you also don't want your benchmarks to
|
||||
incorrectly disable optimizations what would typically happen at render
|
||||
time.
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
AccumRule(int outidx, bool toalpha)
|
||||
: m_outidx(outidx), m_save_to_alpha(toalpha) {};
|
||||
|
||||
/// Called to accumulate from AccumAutomata. It will select the right ouput from
|
||||
/// Called to accumulate from AccumAutomata. It will select the right output from
|
||||
/// the given vector based in the AOV index number (they are guaranteed to match)
|
||||
void accum(const Color3& color, std::vector<AovOutput>& outputs) const;
|
||||
|
||||
|
||||
@@ -43,13 +43,6 @@ struct UniformShaderGlobals {
|
||||
/// way back to the renderer for callbacks.
|
||||
RendererServices* renderer;
|
||||
|
||||
/// The output closure will be placed here. The rendererer should
|
||||
/// initialize this to NULL before shading execution, and this is where
|
||||
/// it can retrieve the output closure from after shader execution has
|
||||
/// completed.
|
||||
/// DESIGN DECISION: NOT CURRENTLY SUPPORTING CLOSURES IN BATCH MODE
|
||||
ClosureColor* Ci;
|
||||
|
||||
/// Bit field of ray type flags.
|
||||
int raytype;
|
||||
|
||||
@@ -59,6 +52,8 @@ struct UniformShaderGlobals {
|
||||
int pad0;
|
||||
int pad1;
|
||||
int pad2;
|
||||
int pad3;
|
||||
int pad4;
|
||||
|
||||
void dump()
|
||||
{
|
||||
@@ -70,7 +65,6 @@ struct UniformShaderGlobals {
|
||||
__OSL_DUMP(objdata);
|
||||
__OSL_DUMP(context);
|
||||
__OSL_DUMP(renderer);
|
||||
__OSL_DUMP(Ci);
|
||||
__OSL_DUMP(raytype);
|
||||
|
||||
std::cout << "};" << std::endl;
|
||||
@@ -129,6 +123,12 @@ template<int WidthT> struct alignas(64) VaryingShaderGlobals {
|
||||
Block<TransformationPtr> object2common;
|
||||
Block<TransformationPtr> shader2common;
|
||||
|
||||
/// The output closure will be placed here. The rendererer should
|
||||
/// initialize this to NULL before shading execution, and this is where
|
||||
/// it can retrieve the output closure from after shader execution has
|
||||
/// completed.
|
||||
Block<ClosureColor*> Ci;
|
||||
|
||||
/// Surface area of the emissive object (used by light shaders for
|
||||
/// energy normalization).
|
||||
Block<float> surfacearea;
|
||||
@@ -168,6 +168,7 @@ template<int WidthT> struct alignas(64) VaryingShaderGlobals {
|
||||
__OSL_DUMP(dPsdy);
|
||||
__OSL_DUMP(object2common);
|
||||
__OSL_DUMP(shader2common);
|
||||
__OSL_DUMP(Ci);
|
||||
__OSL_DUMP(surfacearea);
|
||||
__OSL_DUMP(flipHandedness);
|
||||
__OSL_DUMP(backfacing);
|
||||
|
||||
@@ -135,77 +135,77 @@ static_assert(sizeof(OIIO::TextureOptBatch)
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, sblur)
|
||||
== varying_offset + offsetof(VTO, sblur),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, tblur)
|
||||
== varying_offset + offsetof(VTO, tblur),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, rblur)
|
||||
== varying_offset + offsetof(VTO, rblur),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, swidth)
|
||||
== varying_offset + offsetof(VTO, swidth),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, twidth)
|
||||
== varying_offset + offsetof(VTO, twidth),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, rwidth)
|
||||
== varying_offset + offsetof(VTO, rwidth),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, firstchannel)
|
||||
== uniform_offset + offsetof(UniformTextureOptions, firstchannel),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, subimage)
|
||||
== uniform_offset + offsetof(UniformTextureOptions, subimage),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, subimagename)
|
||||
== uniform_offset + offsetof(UniformTextureOptions, subimagename),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, swrap)
|
||||
== uniform_offset + offsetof(UniformTextureOptions, swrap),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, twrap)
|
||||
== uniform_offset + offsetof(UniformTextureOptions, twrap),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, rwrap)
|
||||
== uniform_offset + offsetof(UniformTextureOptions, rwrap),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, mipmode)
|
||||
== uniform_offset + offsetof(UniformTextureOptions, mipmode),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, interpmode)
|
||||
== uniform_offset + offsetof(UniformTextureOptions, interpmode),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, anisotropic)
|
||||
== uniform_offset + offsetof(UniformTextureOptions, anisotropic),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, conservative_filter)
|
||||
== uniform_offset
|
||||
+ offsetof(UniformTextureOptions, conservative_filter),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, fill)
|
||||
== uniform_offset + offsetof(UniformTextureOptions, fill),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
static_assert(
|
||||
offsetof(OIIO::TextureOptBatch, missingcolor)
|
||||
== uniform_offset + offsetof(UniformTextureOptions, missingcolor),
|
||||
"BatchedTextureOptions members offset different that OIIO::TextureOptBatch");
|
||||
"BatchedTextureOptions members offset different than OIIO::TextureOptBatch");
|
||||
|
||||
OSL_PRAGMA_WARNING_POP
|
||||
} // namespace validate_offsets
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <OSL/oslconfig.h>
|
||||
|
||||
#ifdef __CUDA_ARCH__
|
||||
#include <optix.h>
|
||||
# include <optix.h>
|
||||
#endif
|
||||
|
||||
// USAGE NOTES:
|
||||
@@ -36,20 +36,20 @@ OSL_NAMESPACE_ENTER
|
||||
// stored in the table, in the 16 bytes preceding the characters.
|
||||
|
||||
struct DeviceString {
|
||||
#if defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000
|
||||
size_t m_chars;
|
||||
#ifdef __CUDA_ARCH__
|
||||
size_t m_chars;
|
||||
#else
|
||||
const char* m_chars;
|
||||
#endif
|
||||
|
||||
#if defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000
|
||||
#ifdef __CUDA_ARCH__
|
||||
OSL_HOSTDEVICE DeviceString() {}
|
||||
OSL_HOSTDEVICE DeviceString(uint64_t i) : m_chars(i) {}
|
||||
#endif
|
||||
|
||||
OSL_HOSTDEVICE uint64_t hash() const
|
||||
{
|
||||
#if defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000
|
||||
#ifdef __CUDA_ARCH__
|
||||
return m_chars;
|
||||
#else
|
||||
return *(uint64_t*)(m_chars - sizeof(uint64_t) - sizeof(uint64_t));
|
||||
@@ -58,7 +58,7 @@ struct DeviceString {
|
||||
|
||||
// In OptiX 7 we don't store the string's length. Make this a compile
|
||||
// time error.
|
||||
#if ! (defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000)
|
||||
#ifndef __CUDA_ARCH__
|
||||
OSL_HOSTDEVICE uint64_t length() const
|
||||
{
|
||||
return *(uint64_t*)(m_chars - sizeof(uint64_t));
|
||||
@@ -67,36 +67,39 @@ struct DeviceString {
|
||||
|
||||
// In OptiX 7 we can't return the string's contents. Make this a compile
|
||||
// time error.
|
||||
#if ! (defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000)
|
||||
#ifndef __CUDA_ARCH__
|
||||
OSL_HOSTDEVICE const char* c_str() const
|
||||
{
|
||||
return m_chars;
|
||||
}
|
||||
#endif
|
||||
|
||||
OSL_HOSTDEVICE bool operator== (const DeviceString& other) const
|
||||
OSL_HOSTDEVICE bool operator==(const DeviceString& other) const
|
||||
{
|
||||
return m_chars == other.m_chars;
|
||||
}
|
||||
|
||||
OSL_HOSTDEVICE bool operator!= (const DeviceString& other) const
|
||||
OSL_HOSTDEVICE bool operator!=(const DeviceString& other) const
|
||||
{
|
||||
return m_chars != other.m_chars;
|
||||
}
|
||||
|
||||
#if defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000
|
||||
#ifdef __CUDA_ARCH__
|
||||
|
||||
OSL_HOSTDEVICE bool operator== (const size_t other) const
|
||||
OSL_HOSTDEVICE bool operator==(const size_t other) const
|
||||
{
|
||||
return hash() == other;
|
||||
}
|
||||
|
||||
OSL_HOSTDEVICE bool operator!= (const size_t other) const
|
||||
OSL_HOSTDEVICE bool operator!=(const size_t other) const
|
||||
{
|
||||
return hash() != other;
|
||||
}
|
||||
|
||||
OSL_HOSTDEVICE operator size_t() const { return hash(); }
|
||||
OSL_HOSTDEVICE operator size_t() const
|
||||
{
|
||||
return hash();
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
@@ -106,9 +109,9 @@ struct DeviceString {
|
||||
// macro is the same as the USTR macro defined in oslexec_pvt.h when compiling
|
||||
// for the host.
|
||||
#ifndef __CUDA_ARCH__
|
||||
# define HDSTR(cstr) (*((ustring *)&cstr))
|
||||
# define HDSTR(cstr) (*((ustring*)&cstr))
|
||||
#else
|
||||
#define HDSTR(cstr) (*((OSL::DeviceString*)&cstr))
|
||||
# define HDSTR(cstr) (*((OSL::DeviceString*)&cstr))
|
||||
#endif
|
||||
|
||||
|
||||
@@ -124,25 +127,22 @@ typedef DeviceString StringParam;
|
||||
|
||||
#ifdef __CUDA_ARCH__
|
||||
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
|
||||
}
|
||||
# define STRDECL(str, var_name) \
|
||||
extern __device__ OSL_NAMESPACE::DeviceString var_name;
|
||||
# undef STRDECL
|
||||
} // namespace DeviceStrings
|
||||
#else
|
||||
# define STRING_PARAMS(x) StringParams::x
|
||||
# ifdef OSL_HOST_RS_BITCODE
|
||||
# define STRING_PARAMS(x) RS_##x
|
||||
# else
|
||||
# define STRING_PARAMS(x) StringParams::x
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
OSL_NAMESPACE_EXIT
|
||||
|
||||
|
||||
#ifdef __CUDA_ARCH__
|
||||
#if OPTIX_VERSION < 70000
|
||||
namespace StringParams = OSL_NAMESPACE::DeviceStrings;
|
||||
#endif
|
||||
#else
|
||||
#ifndef __CUDA_ARCH__
|
||||
namespace StringParams = OSL_NAMESPACE::Strings;
|
||||
#endif
|
||||
|
||||
@@ -223,7 +223,7 @@ public:
|
||||
// delegating access to element storage to the DualStorage base class
|
||||
template<
|
||||
class T, // Base data type
|
||||
int PARTIALS=1 // Number of dimentions of partial derivs
|
||||
int PARTIALS=1 // Number of dimensions of partial derivs
|
||||
>
|
||||
class Dual : public DualStorage<T, PARTIALS> {
|
||||
static const int elements = PARTIALS+1; // main value + partials
|
||||
|
||||
+497
-406
File diff suppressed because it is too large
Load Diff
+38
-10
@@ -4,7 +4,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include <OSL/oslconfig.h>
|
||||
@@ -23,6 +22,8 @@ using std::countr_zero;
|
||||
|
||||
#elif OSL_INTEL_CLASSIC_COMPILER_VERSION
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
OSL_FORCEINLINE int popcount(uint32_t x) noexcept { return _mm_popcnt_u32(x);}
|
||||
OSL_FORCEINLINE int popcount(uint64_t x) noexcept { return _mm_popcnt_u64(x); }
|
||||
OSL_FORCEINLINE int countr_zero(uint32_t x) noexcept { return _bit_scan_forward(x); }
|
||||
@@ -170,13 +171,22 @@ public:
|
||||
}
|
||||
|
||||
|
||||
OSL_FORCEINLINE ValueType value() const { return m_value; }
|
||||
OSL_FORCEINLINE ValueType value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
// count number of active bits
|
||||
OSL_FORCEINLINE int count() const { return OSL::popcount(m_value); }
|
||||
OSL_FORCEINLINE int count() const
|
||||
{
|
||||
return OSL::popcount(m_value);
|
||||
}
|
||||
|
||||
// NOTE: undefined result if no bits are on
|
||||
OSL_FORCEINLINE int first_on() const { return OSL::countr_zero(m_value); }
|
||||
OSL_FORCEINLINE int first_on() const
|
||||
{
|
||||
return OSL::countr_zero(m_value);
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE Mask invert() const
|
||||
{
|
||||
@@ -229,7 +239,10 @@ public:
|
||||
return (m_value != static_cast<ValueType>(0));
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE bool any_off() const { return (m_value < valid_bits); }
|
||||
OSL_FORCEINLINE bool any_off() const
|
||||
{
|
||||
return (m_value < valid_bits);
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE bool any_off(const Mask& mask) const
|
||||
{
|
||||
@@ -244,27 +257,39 @@ public:
|
||||
// So really only set_on or set_off is required
|
||||
// Choose to not provide a generic set(int lane, bool flag)
|
||||
|
||||
OSL_FORCEINLINE void set_on(int lane) { m_value |= (1 << lane); }
|
||||
OSL_FORCEINLINE void set_on(int lane)
|
||||
{
|
||||
m_value |= (1 << lane);
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE void set_on_if(int lane, bool cond)
|
||||
{
|
||||
m_value |= (cond << lane);
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE void set_all_on() { m_value = valid_bits; }
|
||||
OSL_FORCEINLINE void set_all_on()
|
||||
{
|
||||
m_value = valid_bits;
|
||||
}
|
||||
OSL_FORCEINLINE void set_count_on(int count)
|
||||
{
|
||||
m_value = valid_bits >> (width - count);
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE void set_off(int lane) { m_value &= (~(1 << lane)); }
|
||||
OSL_FORCEINLINE void set_off(int lane)
|
||||
{
|
||||
m_value &= (~(1 << lane));
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE void set_off_if(int lane, bool cond)
|
||||
{
|
||||
m_value &= (~(cond << lane));
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE void set_all_off() { m_value = static_cast<ValueType>(0); }
|
||||
OSL_FORCEINLINE void set_all_off()
|
||||
{
|
||||
m_value = static_cast<ValueType>(0);
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE bool operator==(const Mask& other) const
|
||||
{
|
||||
@@ -298,7 +323,10 @@ public:
|
||||
return Mask(m_value | other.m_value);
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE Mask operator~() const { return invert(); }
|
||||
OSL_FORCEINLINE Mask operator~() const
|
||||
{
|
||||
return invert();
|
||||
}
|
||||
|
||||
|
||||
template<int MinOccupancyT, int MaxOccupancyT = width, typename FunctorT>
|
||||
|
||||
@@ -109,8 +109,14 @@ OSL_ALIGNAS(16) ClosureComponent : public ClosureColor
|
||||
Vec3 w; ///< Weight of this component
|
||||
|
||||
/// Handy method for getting the parameter memory as a void*.
|
||||
OSL_HOSTDEVICE void* data() { return (char*)(this + 1); }
|
||||
OSL_HOSTDEVICE const void* data() const { return (const char*)(this + 1); }
|
||||
OSL_HOSTDEVICE void* data()
|
||||
{
|
||||
return (char*)(this + 1);
|
||||
}
|
||||
OSL_HOSTDEVICE const void* data() const
|
||||
{
|
||||
return (const char*)(this + 1);
|
||||
}
|
||||
|
||||
/// Handy methods for extracting the underlying parameters as a struct
|
||||
template<typename T> OSL_HOSTDEVICE const T* as() const
|
||||
@@ -140,4 +146,10 @@ struct OSLEXECPUBLIC ClosureAdd : public ClosureColor {
|
||||
const ClosureColor* closureB;
|
||||
};
|
||||
|
||||
/// Type for pointers to closures
|
||||
typedef ClosureColor* ClosureColorPtr;
|
||||
typedef ClosureComponent* ClosureComponentPtr;
|
||||
typedef ClosureAdd* ClosureAddPtr;
|
||||
typedef ClosureMul* ClosureMulPtr;
|
||||
|
||||
OSL_NAMESPACE_EXIT
|
||||
|
||||
@@ -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,3 +225,30 @@ 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
|
||||
|
||||
+286
-237
@@ -29,6 +29,12 @@ template<typename DataT, int WidthT> struct Wide;
|
||||
#endif
|
||||
|
||||
|
||||
/// RendererServices free function bitcode may reference global variables that
|
||||
/// only exist in the renderer's program space and won't automatically be
|
||||
/// found when referenced in JIT'd code inside OSL. A renderer may register
|
||||
/// the addresses of these global variables to allow valid JIT to occur.
|
||||
void OSLEXECPUBLIC
|
||||
register_JIT_Global(const char* global_var_name, void* global_var_addr);
|
||||
|
||||
/// Opaque pointer to whatever the renderer uses to represent a
|
||||
/// (potentially motion-blurred) coordinate transformation.
|
||||
@@ -44,73 +50,73 @@ namespace pvt {
|
||||
class ShadingSystemImpl;
|
||||
}
|
||||
|
||||
#if defined(__CUDA_ARCH__) && OPTIX_VERSION >= 70000
|
||||
# define STRINGIFY(x) XSTR(x)
|
||||
# define XSTR(x) #x
|
||||
# define STRING_PARAMS(x) UStringHash::Hash(STRINGIFY(x))
|
||||
#ifdef __CUDA_ARCH__
|
||||
# define STRING_PARAMS(x) UStringHash::Hash(__OSL_STRINGIFY(x))
|
||||
#else
|
||||
# define STRING_PARAMS(x) StringParams::x
|
||||
# define STRING_PARAMS(x) StringParams::x
|
||||
#endif
|
||||
|
||||
namespace Strings {
|
||||
#ifdef __CUDA_ARCH__
|
||||
# if OPTIX_VERSION >= 70000
|
||||
# define STRDECL(str,var_name)
|
||||
# define STRDECL(str, var_name)
|
||||
#else
|
||||
# define STRDECL(str,var_name) extern __device__ ustring var_name;
|
||||
#endif
|
||||
#else
|
||||
// Any strings referenced inside of a libsoslexec/wide/*.cpp
|
||||
// or liboslnoise/wide/*.cpp will need OSLEXECPUBLIC
|
||||
#define STRDECL(str,var_name) OSLEXECPUBLIC extern const ustring var_name;
|
||||
// Any strings referenced inside of a libsoslexec/wide/*.cpp
|
||||
// or liboslnoise/wide/*.cpp will need OSLEXECPUBLIC
|
||||
# define STRDECL(str, var_name) OSLEXECPUBLIC extern const ustring var_name;
|
||||
#endif
|
||||
#include <OSL/strdecls.h>
|
||||
#undef STRDECL
|
||||
}; // namespace Strings
|
||||
}; // namespace Strings
|
||||
|
||||
|
||||
|
||||
/// Description of where a symbol is located on the app side.
|
||||
struct SymLocationDesc {
|
||||
public:
|
||||
using offset_t = int64_t;
|
||||
using stride_t = int64_t;
|
||||
using offset_t = int64_t;
|
||||
using stride_t = int64_t;
|
||||
static const int64_t AutoStride = std::numeric_limits<stride_t>::min();
|
||||
|
||||
SymLocationDesc() {}
|
||||
SymLocationDesc(string_view name, TypeDesc type, bool derivs = false,
|
||||
SymArena arena = SymArena::Heap, offset_t offset = -1,
|
||||
stride_t stride = AutoStride)
|
||||
: name(name), type(type), offset(offset),
|
||||
stride(stride == AutoStride ? type.size() : stride),
|
||||
arena(arena), derivs(derivs)
|
||||
{}
|
||||
: name(name)
|
||||
, type(type)
|
||||
, offset(offset)
|
||||
, stride(stride == AutoStride ? type.size() : stride)
|
||||
, arena(arena)
|
||||
, derivs(derivs)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(ustring n) const { return name == n; }
|
||||
friend bool operator<(ustring n, const SymLocationDesc& sld) {
|
||||
friend bool operator<(ustring n, const SymLocationDesc& sld)
|
||||
{
|
||||
return n < sld.name;
|
||||
}
|
||||
friend bool operator<(const SymLocationDesc& sld, ustring n) {
|
||||
friend bool operator<(const SymLocationDesc& sld, ustring n)
|
||||
{
|
||||
return sld.name < n;
|
||||
}
|
||||
|
||||
ustring name; ///< Name of the symbol
|
||||
TypeDesc type; ///< Data type of the symbol
|
||||
offset_t offset = -1; ///< Offset from arena base for point 0 (batched mode assumes userdata at point 0 is readable)
|
||||
stride_t stride = AutoStride; ///< Stride in bytes between shade points
|
||||
SymArena arena = SymArena::Heap; ///< Memory arena type for the symbol
|
||||
bool derivs = false; ///< Space allocated for derivs also
|
||||
ustring name; ///< Name of the symbol
|
||||
TypeDesc type; ///< Data type of the symbol
|
||||
offset_t offset
|
||||
= -1; ///< Offset from arena base for point 0 (batched mode assumes userdata at point 0 is readable)
|
||||
stride_t stride = AutoStride; ///< Stride in bytes between shade points
|
||||
SymArena arena = SymArena::Heap; ///< Memory arena type for the symbol
|
||||
bool derivs = false; ///< Space allocated for derivs also
|
||||
};
|
||||
|
||||
|
||||
|
||||
class OSLEXECPUBLIC ShadingSystem
|
||||
{
|
||||
class OSLEXECPUBLIC ShadingSystem {
|
||||
public:
|
||||
ShadingSystem (RendererServices *renderer=NULL,
|
||||
TextureSystem *texturesystem=NULL,
|
||||
ErrorHandler *err=NULL);
|
||||
~ShadingSystem ();
|
||||
ShadingSystem(RendererServices* renderer = NULL,
|
||||
TextureSystem* texturesystem = NULL,
|
||||
ErrorHandler* err = NULL);
|
||||
~ShadingSystem();
|
||||
|
||||
/// Set an attribute controlling the shading system. Return true
|
||||
/// if the name and type were recognized and the attrib was set.
|
||||
@@ -225,8 +231,7 @@ 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],
|
||||
/// "internalize", or "none").
|
||||
/// IR (choices: "prune" [default], 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
|
||||
@@ -241,23 +246,27 @@ public:
|
||||
/// 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!
|
||||
bool attribute (string_view name, TypeDesc type, const void *val);
|
||||
bool attribute(string_view name, TypeDesc type, const void* val);
|
||||
|
||||
// Shortcuts for common types
|
||||
bool attribute (string_view name, int val) {
|
||||
return attribute (name, TypeDesc::INT, &val);
|
||||
bool attribute(string_view name, int val)
|
||||
{
|
||||
return attribute(name, TypeDesc::INT, &val);
|
||||
}
|
||||
bool attribute (string_view name, float val) {
|
||||
return attribute (name, TypeDesc::FLOAT, &val);
|
||||
bool attribute(string_view name, float val)
|
||||
{
|
||||
return attribute(name, TypeDesc::FLOAT, &val);
|
||||
}
|
||||
bool attribute (string_view name, double val) {
|
||||
float f = (float) val;
|
||||
return attribute (name, TypeDesc::FLOAT, &f);
|
||||
bool attribute(string_view name, double val)
|
||||
{
|
||||
float f = (float)val;
|
||||
return attribute(name, TypeDesc::FLOAT, &f);
|
||||
}
|
||||
bool attribute (string_view name, string_view val) {
|
||||
bool attribute(string_view name, string_view val)
|
||||
{
|
||||
std::string valstr(val);
|
||||
const char *s = valstr.c_str();
|
||||
return attribute (name, TypeDesc::STRING, &s);
|
||||
const char* s = valstr.c_str();
|
||||
return attribute(name, TypeDesc::STRING, &s);
|
||||
}
|
||||
|
||||
|
||||
@@ -273,22 +282,26 @@ public:
|
||||
/// called unconditionally.
|
||||
/// int exec_repeat How many times to run the group (1).
|
||||
///
|
||||
bool attribute (ShaderGroup *group, string_view name,
|
||||
TypeDesc type, const void *val);
|
||||
bool attribute (ShaderGroup *group, string_view name, int val) {
|
||||
return attribute (group, name, TypeDesc::INT, &val);
|
||||
bool attribute(ShaderGroup* group, string_view name, TypeDesc type,
|
||||
const void* val);
|
||||
bool attribute(ShaderGroup* group, string_view name, int val)
|
||||
{
|
||||
return attribute(group, name, TypeDesc::INT, &val);
|
||||
}
|
||||
bool attribute (ShaderGroup *group, string_view name, float val) {
|
||||
return attribute (group, name, TypeDesc::FLOAT, &val);
|
||||
bool attribute(ShaderGroup* group, string_view name, float val)
|
||||
{
|
||||
return attribute(group, name, TypeDesc::FLOAT, &val);
|
||||
}
|
||||
bool attribute (ShaderGroup *group, string_view name, double val) {
|
||||
float f = (float) val;
|
||||
return attribute (group, name, TypeDesc::FLOAT, &f);
|
||||
bool attribute(ShaderGroup* group, string_view name, double val)
|
||||
{
|
||||
float f = (float)val;
|
||||
return attribute(group, name, TypeDesc::FLOAT, &f);
|
||||
}
|
||||
bool attribute (ShaderGroup *group, string_view name, string_view val) {
|
||||
bool attribute(ShaderGroup* group, string_view name, string_view val)
|
||||
{
|
||||
std::string valstr(val);
|
||||
const char *s = valstr.c_str();
|
||||
return attribute (group, name, TypeDesc::STRING, &s);
|
||||
const char* s = valstr.c_str();
|
||||
return attribute(group, name, TypeDesc::STRING, &s);
|
||||
}
|
||||
|
||||
/// Get the named attribute of the ShadingSystem, store it in `*val`.
|
||||
@@ -318,23 +331,26 @@ public:
|
||||
/// library build dependencies and their versions (for example,
|
||||
/// "OIIO-2.3.0,LLVM-10.0.0,OpenEXR-2.5.0").
|
||||
///
|
||||
bool getattribute (string_view name, TypeDesc type, void *val);
|
||||
bool getattribute(string_view name, TypeDesc type, void* val);
|
||||
|
||||
/// Shortcut getattribute() for retrieving a single integer.
|
||||
/// The value is placed in `val`, and the function returns `true` if the
|
||||
/// attribute was found and was legally convertible to an int.
|
||||
bool getattribute (string_view name, int &val) {
|
||||
return getattribute (name, TypeDesc::INT, &val);
|
||||
bool getattribute(string_view name, int& val)
|
||||
{
|
||||
return getattribute(name, TypeDesc::INT, &val);
|
||||
}
|
||||
/// Shortcut getattribute() for retrieving a single float.
|
||||
/// The value is placed in `val`, and the function returns `true` if the
|
||||
/// attribute was found and was legally convertible to a float.
|
||||
bool getattribute (string_view name, float &val) {
|
||||
return getattribute (name, TypeDesc::FLOAT, &val);
|
||||
bool getattribute(string_view name, float& val)
|
||||
{
|
||||
return getattribute(name, TypeDesc::FLOAT, &val);
|
||||
}
|
||||
bool getattribute (string_view name, double &val) {
|
||||
bool getattribute(string_view name, double& val)
|
||||
{
|
||||
float f;
|
||||
bool ok = getattribute (name, TypeDesc::FLOAT, &f);
|
||||
bool ok = getattribute(name, TypeDesc::FLOAT, &f);
|
||||
if (ok)
|
||||
val = f;
|
||||
return ok;
|
||||
@@ -342,21 +358,24 @@ public:
|
||||
/// Shortcut getattribute() for retrieving a single string as a
|
||||
/// `const char*`. The value is placed in `val`, and the function
|
||||
/// returns `true` if the attribute was found.
|
||||
bool getattribute (string_view name, char **val) {
|
||||
return getattribute (name, TypeDesc::STRING, val);
|
||||
bool getattribute(string_view name, char** val)
|
||||
{
|
||||
return getattribute(name, TypeDesc::STRING, val);
|
||||
}
|
||||
/// Shortcut getattribute() for retrieving a single string as a
|
||||
/// `ustring`. The value is placed in `val`, and the function returns
|
||||
/// `true` if the attribute was found.
|
||||
bool getattribute (string_view name, ustring &val) {
|
||||
return getattribute (name, TypeDesc::STRING, (char **)&val);
|
||||
bool getattribute(string_view name, ustring& val)
|
||||
{
|
||||
return getattribute(name, TypeDesc::STRING, (char**)&val);
|
||||
}
|
||||
/// Shortcut getattribute() for retrieving a single string as a
|
||||
/// `std::string`. The value is placed in `val`, and the function
|
||||
/// returns `true` if the attribute was found.
|
||||
bool getattribute (string_view name, std::string &val) {
|
||||
const char *s = NULL;
|
||||
bool ok = getattribute (name, TypeDesc::STRING, &s);
|
||||
bool getattribute(string_view name, std::string& val)
|
||||
{
|
||||
const char* s = NULL;
|
||||
bool ok = getattribute(name, TypeDesc::STRING, &s);
|
||||
if (ok)
|
||||
val = s;
|
||||
return ok;
|
||||
@@ -427,31 +446,37 @@ public:
|
||||
/// 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!
|
||||
bool getattribute (ShaderGroup *group, string_view name,
|
||||
TypeDesc type, void *val);
|
||||
bool getattribute(ShaderGroup* group, string_view name, TypeDesc type,
|
||||
void* val);
|
||||
// Shortcuts for common types
|
||||
bool getattribute (ShaderGroup *group, string_view name, int &val) {
|
||||
return getattribute (group, name, TypeDesc::INT, &val);
|
||||
bool getattribute(ShaderGroup* group, string_view name, int& val)
|
||||
{
|
||||
return getattribute(group, name, TypeDesc::INT, &val);
|
||||
}
|
||||
bool getattribute (ShaderGroup *group, string_view name, float &val) {
|
||||
return getattribute (group, name, TypeDesc::FLOAT, &val);
|
||||
bool getattribute(ShaderGroup* group, string_view name, float& val)
|
||||
{
|
||||
return getattribute(group, name, TypeDesc::FLOAT, &val);
|
||||
}
|
||||
bool getattribute (ShaderGroup *group, string_view name, double &val) {
|
||||
bool getattribute(ShaderGroup* group, string_view name, double& val)
|
||||
{
|
||||
float f;
|
||||
bool ok = getattribute (group, name, TypeDesc::FLOAT, &f);
|
||||
bool ok = getattribute(group, name, TypeDesc::FLOAT, &f);
|
||||
if (ok)
|
||||
val = f;
|
||||
return ok;
|
||||
}
|
||||
bool getattribute (ShaderGroup *group, string_view name, char **val) {
|
||||
return getattribute (group, name, TypeDesc::STRING, val);
|
||||
bool getattribute(ShaderGroup* group, string_view name, char** val)
|
||||
{
|
||||
return getattribute(group, name, TypeDesc::STRING, val);
|
||||
}
|
||||
bool getattribute (ShaderGroup *group, string_view name, ustring &val) {
|
||||
return getattribute (group, name, TypeDesc::STRING, (char **)&val);
|
||||
bool getattribute(ShaderGroup* group, string_view name, ustring& val)
|
||||
{
|
||||
return getattribute(group, name, TypeDesc::STRING, (char**)&val);
|
||||
}
|
||||
bool getattribute (ShaderGroup *group, string_view name, std::string &val) {
|
||||
const char *s = NULL;
|
||||
bool ok = getattribute (group, name, TypeDesc::STRING, &s);
|
||||
bool getattribute(ShaderGroup* group, string_view name, std::string& val)
|
||||
{
|
||||
const char* s = NULL;
|
||||
bool ok = getattribute(group, name, TypeDesc::STRING, &s);
|
||||
if (ok)
|
||||
val = s;
|
||||
return ok;
|
||||
@@ -460,8 +485,7 @@ public:
|
||||
|
||||
/// Load compiled shader (oso) from a memory buffer, overriding
|
||||
/// shader lookups in the shader search path
|
||||
bool LoadMemoryCompiledShader (string_view shadername,
|
||||
string_view buffer);
|
||||
bool LoadMemoryCompiledShader(string_view shadername, string_view buffer);
|
||||
|
||||
// The basic sequence for declaring a shader group looks like this:
|
||||
// ShadingSystem *ss = ...;
|
||||
@@ -487,7 +511,7 @@ public:
|
||||
|
||||
/// Signal the start of a new shader group. The return value is a
|
||||
/// reference-counted opaque handle to the ShaderGroup.
|
||||
ShaderGroupRef ShaderGroupBegin (string_view groupname = string_view());
|
||||
ShaderGroupRef ShaderGroupBegin(string_view groupname = string_view());
|
||||
|
||||
/// Alternate way to specify a shader group. The group specification
|
||||
/// syntax looks like this: (as a string, all whitespace is equivalent):
|
||||
@@ -497,13 +521,13 @@ public:
|
||||
/// For the sake of easy assembling on command lines, a comma ',' may
|
||||
/// substitute for the semicolon as a separator, and the last separator
|
||||
/// before the end of the string is optional.
|
||||
ShaderGroupRef ShaderGroupBegin (string_view groupname,
|
||||
string_view shaderusage,
|
||||
string_view groupspec = string_view());
|
||||
ShaderGroupRef ShaderGroupBegin(string_view groupname,
|
||||
string_view shaderusage,
|
||||
string_view groupspec = string_view());
|
||||
|
||||
/// Signal the end of a new shader group.
|
||||
///
|
||||
bool ShaderGroupEnd (ShaderGroup& group);
|
||||
bool ShaderGroupEnd(ShaderGroup& group);
|
||||
|
||||
/// Set a parameter of the next shader that will be added to the group,
|
||||
/// optionally setting the 'lockgeom' metadata for that parameter
|
||||
@@ -512,32 +536,37 @@ public:
|
||||
/// against changes by the geometry, and therefore the shader should not
|
||||
/// optimize assuming that the instance value (the 'val' specified by
|
||||
/// this call) is a constant.
|
||||
bool Parameter (ShaderGroup& group, string_view name, TypeDesc t,
|
||||
const void *val, bool lockgeom=true);
|
||||
bool Parameter(ShaderGroup& group, string_view name, TypeDesc t,
|
||||
const void* val, bool lockgeom = true);
|
||||
// Shortcuts for param passing a single int, float, or string.
|
||||
bool Parameter (ShaderGroup& group, string_view name,
|
||||
int val, bool lockgeom=true) {
|
||||
return Parameter (group, name, TypeDesc::INT, &val, lockgeom);
|
||||
bool Parameter(ShaderGroup& group, string_view name, int val,
|
||||
bool lockgeom = true)
|
||||
{
|
||||
return Parameter(group, name, TypeDesc::INT, &val, lockgeom);
|
||||
}
|
||||
bool Parameter (ShaderGroup& group, string_view name,
|
||||
float val, bool lockgeom=true) {
|
||||
return Parameter (group, name, TypeDesc::FLOAT, &val, lockgeom);
|
||||
bool Parameter(ShaderGroup& group, string_view name, float val,
|
||||
bool lockgeom = true)
|
||||
{
|
||||
return Parameter(group, name, TypeDesc::FLOAT, &val, lockgeom);
|
||||
}
|
||||
bool Parameter (ShaderGroup& group, string_view name,
|
||||
const std::string& val, bool lockgeom=true) {
|
||||
const char *s = val.c_str();
|
||||
return Parameter (group, name, TypeDesc::STRING, &s, lockgeom);
|
||||
bool Parameter(ShaderGroup& group, string_view name, const std::string& val,
|
||||
bool lockgeom = true)
|
||||
{
|
||||
const char* s = val.c_str();
|
||||
return Parameter(group, name, TypeDesc::STRING, &s, lockgeom);
|
||||
}
|
||||
bool Parameter (ShaderGroup& group, string_view name,
|
||||
ustring val, bool lockgeom=true) {
|
||||
return Parameter (group, name, TypeDesc::STRING, (const char**)&val, lockgeom);
|
||||
bool Parameter(ShaderGroup& group, string_view name, ustring val,
|
||||
bool lockgeom = true)
|
||||
{
|
||||
return Parameter(group, name, TypeDesc::STRING, (const char**)&val,
|
||||
lockgeom);
|
||||
}
|
||||
|
||||
/// Append a new shader instance onto the specified group. The shader
|
||||
/// instance will get any pending parameters that were set by
|
||||
/// Parameter() calls since the last Shader() call for the group.
|
||||
bool Shader (ShaderGroup& group, string_view shaderusage,
|
||||
string_view shadername, string_view layername);
|
||||
bool Shader(ShaderGroup& group, string_view shaderusage,
|
||||
string_view shadername, string_view layername);
|
||||
|
||||
/// Connect two shaders within the specified group. The source layer
|
||||
/// must be *upstream* of down destination layer (i.e. source must be
|
||||
@@ -553,9 +582,9 @@ public:
|
||||
/// `ConnectShaders (group, "lay1", "mycolorout[2]",
|
||||
/// "lay2", "myfloatinput")`
|
||||
///
|
||||
bool ConnectShaders (ShaderGroup &group,
|
||||
string_view srclayer, string_view srcparam,
|
||||
string_view dstlayer, string_view dstparam);
|
||||
bool ConnectShaders(ShaderGroup& group, string_view srclayer,
|
||||
string_view srcparam, string_view dstlayer,
|
||||
string_view dstparam);
|
||||
|
||||
/// Replace a parameter value in a previously-declared shader group.
|
||||
/// This is meant to called after the ShaderGroupBegin/End, but will
|
||||
@@ -564,27 +593,30 @@ public:
|
||||
/// indicates that it's a parameter that may be overridden by the
|
||||
/// geometric primitive). This call gives you a way of changing the
|
||||
/// instance value, even if it's not a geometric override.
|
||||
bool ReParameter (ShaderGroup &group,
|
||||
string_view layername, string_view paramname,
|
||||
TypeDesc type, const void *val);
|
||||
bool ReParameter(ShaderGroup& group, string_view layername,
|
||||
string_view paramname, TypeDesc type, const void* val);
|
||||
// Shortcuts for param passing a single int, float, or string.
|
||||
bool ReParameter (ShaderGroup &group, string_view layername,
|
||||
string_view paramname, int val) {
|
||||
return ReParameter (group, layername, paramname, TypeDesc::INT, &val);
|
||||
bool ReParameter(ShaderGroup& group, string_view layername,
|
||||
string_view paramname, int val)
|
||||
{
|
||||
return ReParameter(group, layername, paramname, TypeDesc::INT, &val);
|
||||
}
|
||||
bool ReParameter (ShaderGroup &group, string_view layername,
|
||||
string_view paramname, float val) {
|
||||
return ReParameter (group, layername, paramname, TypeDesc::FLOAT, &val);
|
||||
bool ReParameter(ShaderGroup& group, string_view layername,
|
||||
string_view paramname, float val)
|
||||
{
|
||||
return ReParameter(group, layername, paramname, TypeDesc::FLOAT, &val);
|
||||
}
|
||||
bool ReParameter (ShaderGroup &group, string_view layername,
|
||||
string_view paramname, const std::string& val) {
|
||||
const char *s = val.c_str();
|
||||
return ReParameter (group, layername, paramname, TypeDesc::STRING, &s);
|
||||
bool ReParameter(ShaderGroup& group, string_view layername,
|
||||
string_view paramname, const std::string& val)
|
||||
{
|
||||
const char* s = val.c_str();
|
||||
return ReParameter(group, layername, paramname, TypeDesc::STRING, &s);
|
||||
}
|
||||
bool ReParameter (ShaderGroup &group, string_view layername,
|
||||
string_view paramname, ustring val) {
|
||||
return ReParameter (group, layername, paramname, TypeDesc::STRING,
|
||||
(const char**)&val);
|
||||
bool ReParameter(ShaderGroup& group, string_view layername,
|
||||
string_view paramname, ustring val)
|
||||
{
|
||||
return ReParameter(group, layername, paramname, TypeDesc::STRING,
|
||||
(const char**)&val);
|
||||
}
|
||||
|
||||
// Non-threadsafe versions of Parameter, Shader, ConnectShaders, and
|
||||
@@ -595,13 +627,13 @@ public:
|
||||
// concurrently). If there is any doubt about that, use the versions
|
||||
// above that take an explicit `ShaderGroup&`, which are thread-safe
|
||||
// and re-entrant.
|
||||
bool Parameter (string_view name, TypeDesc t, const void *val,
|
||||
bool lockgeom=true);
|
||||
bool Shader (string_view shaderusage, string_view shadername,
|
||||
string_view layername);
|
||||
bool ConnectShaders (string_view srclayer, string_view srcparam,
|
||||
string_view dstlayer, string_view dstparam);
|
||||
bool ShaderGroupEnd (void);
|
||||
bool Parameter(string_view name, TypeDesc t, const void* val,
|
||||
bool lockgeom = true);
|
||||
bool Shader(string_view shaderusage, string_view shadername,
|
||||
string_view layername);
|
||||
bool ConnectShaders(string_view srclayer, string_view srcparam,
|
||||
string_view dstlayer, string_view dstparam);
|
||||
bool ShaderGroupEnd(void);
|
||||
|
||||
/// Create a per-thread data needed for shader execution. It's very
|
||||
/// important for the app to never use a PerThreadInfo from more than
|
||||
@@ -609,11 +641,11 @@ public:
|
||||
/// for each renderer thread), and destroy it with destroy_thread_info
|
||||
/// when the thread terminates (and before the ShadingSystem is
|
||||
/// destroyed).
|
||||
PerThreadInfo * create_thread_info();
|
||||
PerThreadInfo* create_thread_info();
|
||||
|
||||
/// Destroy a PerThreadInfo that was allocated by
|
||||
/// create_thread_info().
|
||||
void destroy_thread_info (PerThreadInfo *threadinfo);
|
||||
void destroy_thread_info(PerThreadInfo* threadinfo);
|
||||
|
||||
/// Get a ShadingContext that we can use. The context is specific to a
|
||||
/// renderer thread, and should never be passed between or shared by
|
||||
@@ -621,12 +653,13 @@ public:
|
||||
/// thread-specific pointer created by create_thread_info. The context
|
||||
/// can be used to shade many points; a typical usage is to allocate
|
||||
/// just one context per thread and use it for the whole run.
|
||||
ShadingContext *get_context (PerThreadInfo *threadinfo,
|
||||
TextureSystem::Perthread *texture_threadinfo=NULL);
|
||||
ShadingContext*
|
||||
get_context(PerThreadInfo* threadinfo,
|
||||
TextureSystem::Perthread* texture_threadinfo = NULL);
|
||||
|
||||
/// Return a ShadingContext to the pool.
|
||||
///
|
||||
void release_context (ShadingContext *ctx);
|
||||
void release_context(ShadingContext* ctx);
|
||||
|
||||
/// Execute the shader group in this context on shading point
|
||||
/// `shadeindex`. If ctx is nullptr, then execute will request one
|
||||
@@ -635,19 +668,30 @@ public:
|
||||
/// execute_layer of the last (presumably group entry) layer, and
|
||||
/// execute_cleanup. If run==false, just do the binding and setup, don't
|
||||
/// actually run the shader.
|
||||
bool execute(ShadingContext &ctx, ShaderGroup &group, int shadeindex,
|
||||
bool execute(ShadingContext& ctx, ShaderGroup& group, int shadeindex,
|
||||
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) {
|
||||
bool execute(ShadingContext& ctx, ShaderGroup& group,
|
||||
ShaderGlobals& globals, bool run = true)
|
||||
{
|
||||
return execute(ctx, group, 0, globals, nullptr, nullptr, run);
|
||||
}
|
||||
|
||||
// DEPRECATED(2.0): ctx pointer
|
||||
bool execute (ShadingContext *ctx, ShaderGroup &group,
|
||||
ShaderGlobals &globals, bool run=true) {
|
||||
bool execute(ShadingContext* ctx, ShaderGroup& group,
|
||||
ShaderGlobals& globals, bool run = true)
|
||||
{
|
||||
return execute(*ctx, group, globals, run);
|
||||
}
|
||||
|
||||
@@ -659,12 +703,13 @@ public:
|
||||
/// preparation, but don't actually run the shader. Return true if the
|
||||
/// shader executed, false if it did not (including if the shader itself
|
||||
/// was empty).
|
||||
bool execute_init(ShadingContext &ctx, ShaderGroup &group, int shadeindex,
|
||||
ShaderGlobals &globals, void* userdata_base_ptr,
|
||||
void* output_base_ptr, bool run=true);
|
||||
bool execute_init(ShadingContext& ctx, ShaderGroup& group, int shadeindex,
|
||||
ShaderGlobals& globals, void* userdata_base_ptr,
|
||||
void* output_base_ptr, bool run = true);
|
||||
// DEPRECATED(2.0): no shadeindex or base pointers
|
||||
bool execute_init (ShadingContext &ctx, ShaderGroup &group,
|
||||
ShaderGlobals &globals, bool run=true) {
|
||||
bool execute_init(ShadingContext& ctx, ShaderGroup& group,
|
||||
ShaderGlobals& globals, bool run = true)
|
||||
{
|
||||
return execute_init(ctx, group, 0, globals, nullptr, nullptr, run);
|
||||
}
|
||||
|
||||
@@ -673,41 +718,44 @@ public:
|
||||
/// run==true, and that the call to execute_init() returned true. (One
|
||||
/// reason why it might have returned false is if the shader group
|
||||
/// turned out, after optimization, to do nothing.)
|
||||
bool execute_layer(ShadingContext &ctx, int shadeindex, ShaderGlobals &globals,
|
||||
void* userdata_base_ptr, void* output_base_ptr,
|
||||
int layernumber);
|
||||
bool execute_layer(ShadingContext& ctx, int shadeindex,
|
||||
ShaderGlobals& globals, void* userdata_base_ptr,
|
||||
void* output_base_ptr, int layernumber);
|
||||
/// Execute the layer by name.
|
||||
bool execute_layer(ShadingContext &ctx, int shadeindex, ShaderGlobals &globals,
|
||||
void* userdata_base_ptr, void* output_base_ptr,
|
||||
ustring layername);
|
||||
bool execute_layer(ShadingContext& ctx, int shadeindex,
|
||||
ShaderGlobals& globals, void* userdata_base_ptr,
|
||||
void* output_base_ptr, ustring layername);
|
||||
/// Execute the layer that has the given ShaderSymbol as an output.
|
||||
/// (The symbol is one returned by find_symbol()).
|
||||
bool execute_layer(ShadingContext &ctx, int shadeindex, ShaderGlobals &globals,
|
||||
void* userdata_base_ptr, void* output_base_ptr,
|
||||
const ShaderSymbol *symbol);
|
||||
bool execute_layer(ShadingContext& ctx, int shadeindex,
|
||||
ShaderGlobals& globals, void* userdata_base_ptr,
|
||||
void* output_base_ptr, const ShaderSymbol* symbol);
|
||||
|
||||
// DEPRECATED(2.0): no shadeindex or base pointers
|
||||
bool execute_layer (ShadingContext &ctx, ShaderGlobals &globals,
|
||||
int layernumber) {
|
||||
bool execute_layer(ShadingContext& ctx, ShaderGlobals& globals,
|
||||
int layernumber)
|
||||
{
|
||||
return execute_layer(ctx, 0, globals, nullptr, nullptr, layernumber);
|
||||
}
|
||||
bool execute_layer (ShadingContext &ctx, ShaderGlobals &globals,
|
||||
ustring layername) {
|
||||
bool execute_layer(ShadingContext& ctx, ShaderGlobals& globals,
|
||||
ustring layername)
|
||||
{
|
||||
return execute_layer(ctx, 0, globals, nullptr, nullptr, layername);
|
||||
}
|
||||
bool execute_layer (ShadingContext &ctx, ShaderGlobals &globals,
|
||||
const ShaderSymbol *symbol) {
|
||||
bool execute_layer(ShadingContext& ctx, ShaderGlobals& globals,
|
||||
const ShaderSymbol* symbol)
|
||||
{
|
||||
return execute_layer(ctx, 0, globals, nullptr, nullptr, symbol);
|
||||
}
|
||||
|
||||
/// Signify that the context is done with the current execution of the
|
||||
/// group that was kicked off by execute_init and one or more calls to
|
||||
/// execute_layer.
|
||||
bool execute_cleanup (ShadingContext &ctx);
|
||||
bool execute_cleanup(ShadingContext& ctx);
|
||||
|
||||
/// Find the named layer within a group and return its index, or -1
|
||||
/// if no such named layer exists.
|
||||
int find_layer (const ShaderGroup &group, ustring layername) const;
|
||||
int find_layer(const ShaderGroup& group, ustring layername) const;
|
||||
|
||||
/// Get a raw pointer to a named symbol (such as you'd need to pull
|
||||
/// out the value of an output parameter). ctx is the shading
|
||||
@@ -724,10 +772,10 @@ public:
|
||||
///
|
||||
/// These are considered somewhat deprecated, in favor of using
|
||||
/// find_symbol(), symbol_typedesc(), and symbol_address().
|
||||
const void* get_symbol (const ShadingContext &ctx, ustring layername,
|
||||
ustring symbolname, TypeDesc &type) const;
|
||||
const void* get_symbol (const ShadingContext &ctx, ustring symbolname,
|
||||
TypeDesc &type) const;
|
||||
const void* get_symbol(const ShadingContext& ctx, ustring layername,
|
||||
ustring symbolname, TypeDesc& type) const;
|
||||
const void* get_symbol(const ShadingContext& ctx, ustring symbolname,
|
||||
TypeDesc& type) const;
|
||||
|
||||
/// Search for an output symbol by name (and optionally, layer) within
|
||||
/// the optimized shader group. If the symbol is found, return an opaque
|
||||
@@ -741,22 +789,22 @@ public:
|
||||
/// separately, or by concatenating "layername.symbolname", but note
|
||||
/// that the latter will involve string manipulation inside find_symbol
|
||||
/// and is much more expensive than specifying them separately.
|
||||
const ShaderSymbol* find_symbol (const ShaderGroup &group,
|
||||
ustring layername, ustring symbolname) const;
|
||||
const ShaderSymbol* find_symbol (const ShaderGroup &group,
|
||||
ustring symbolname) const;
|
||||
const ShaderSymbol* find_symbol(const ShaderGroup& group, ustring layername,
|
||||
ustring symbolname) const;
|
||||
const ShaderSymbol* find_symbol(const ShaderGroup& group,
|
||||
ustring symbolname) const;
|
||||
|
||||
/// Given an opaque ShaderSymbol*, return the TypeDesc describing it.
|
||||
/// Note that a closure will end up with a TypeDesc::UNKNOWN value.
|
||||
TypeDesc symbol_typedesc (const ShaderSymbol *sym) const;
|
||||
TypeDesc symbol_typedesc(const ShaderSymbol* sym) const;
|
||||
|
||||
/// Given a context (that has executed a shader) and an opaque
|
||||
/// ShaderSymbol*, return the actual memory address where the value of
|
||||
/// the symbol resides within the heap memory of the context. This
|
||||
/// is only valid for the shader execution that had happened immediately
|
||||
/// prior for this context, but it is a very inexpensive operation.
|
||||
const void* symbol_address (const ShadingContext &ctx,
|
||||
const ShaderSymbol *sym) const;
|
||||
const void* symbol_address(const ShadingContext& ctx,
|
||||
const ShaderSymbol* sym) const;
|
||||
|
||||
#if OSL_USE_BATCHED
|
||||
/// Based on currently set attributes for llvm_jit_target and
|
||||
@@ -767,54 +815,56 @@ public:
|
||||
/// Returns true if supported, false otherwise
|
||||
bool configure_batch_execution_at(int width);
|
||||
|
||||
template<int WidthT>
|
||||
class OSLEXECPUBLIC BatchedExecutor {
|
||||
ShadingSystem & m_shading_system;
|
||||
template<int WidthT> class OSLEXECPUBLIC BatchedExecutor {
|
||||
ShadingSystem& m_shading_system;
|
||||
|
||||
public:
|
||||
explicit OSL_FORCEINLINE BatchedExecutor(ShadingSystem & ss)
|
||||
:m_shading_system(ss)
|
||||
{}
|
||||
explicit OSL_FORCEINLINE BatchedExecutor(ShadingSystem& ss)
|
||||
: m_shading_system(ss)
|
||||
{
|
||||
}
|
||||
OSL_FORCEINLINE BatchedExecutor(const BatchedExecutor&) = default;
|
||||
|
||||
/// Ensure that the group has been JITed.
|
||||
void jit_group (ShaderGroup *group, ShadingContext *ctx);
|
||||
void jit_group(ShaderGroup* group, ShadingContext* ctx);
|
||||
|
||||
/// If option "greedyjit" was set, this call will trigger all
|
||||
/// shader groups that have not yet been compiled to do so with the
|
||||
/// specified number of threads (0 means use all available HW cores).
|
||||
void jit_all_groups (int nthreads=0);
|
||||
void jit_all_groups(int nthreads = 0);
|
||||
|
||||
bool execute (ShadingContext &ctx, ShaderGroup &group, int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT> &globals_batch,
|
||||
void* userdata_base_ptr,
|
||||
void* output_base_ptr, bool run=true);
|
||||
bool execute(ShadingContext& ctx, ShaderGroup& group, int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT>& globals_batch,
|
||||
void* userdata_base_ptr, void* output_base_ptr,
|
||||
bool run = true);
|
||||
|
||||
bool execute_init (ShadingContext &ctx, ShaderGroup &group, int batch_size,
|
||||
bool execute_init(ShadingContext& ctx, ShaderGroup& group,
|
||||
int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT>& globals_batch,
|
||||
void* userdata_base_ptr, void* output_base_ptr,
|
||||
bool run = true);
|
||||
|
||||
bool execute_layer(ShadingContext& ctx, int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT> &globals_batch,
|
||||
void* userdata_base_ptr,
|
||||
void* output_base_ptr, bool run=true);
|
||||
|
||||
bool execute_layer (ShadingContext &ctx, int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT> &globals_batch,
|
||||
void* userdata_base_ptr,
|
||||
void* output_base_ptr, int layernumber);
|
||||
bool execute_layer (ShadingContext &ctx, int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT> &globals_batch,
|
||||
void* userdata_base_ptr,
|
||||
void* output_base_ptr, ustring layername);
|
||||
bool execute_layer (ShadingContext &ctx, int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT> &globals_batch,
|
||||
void* userdata_base_ptr,
|
||||
void* output_base_ptr, const ShaderSymbol *symbol);
|
||||
BatchedShaderGlobals<WidthT>& globals_batch,
|
||||
void* userdata_base_ptr, void* output_base_ptr,
|
||||
int layernumber);
|
||||
bool execute_layer(ShadingContext& ctx, int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT>& globals_batch,
|
||||
void* userdata_base_ptr, void* output_base_ptr,
|
||||
ustring layername);
|
||||
bool execute_layer(ShadingContext& ctx, int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT>& globals_batch,
|
||||
void* userdata_base_ptr, void* output_base_ptr,
|
||||
const ShaderSymbol* symbol);
|
||||
};
|
||||
|
||||
template<int WidthT>
|
||||
OSL_FORCEINLINE BatchedExecutor<WidthT> batched() {
|
||||
template<int WidthT> OSL_FORCEINLINE BatchedExecutor<WidthT> batched()
|
||||
{
|
||||
return BatchedExecutor<WidthT>(*this);
|
||||
}
|
||||
#endif
|
||||
@@ -822,37 +872,36 @@ public:
|
||||
|
||||
/// Return the statistics output as a huge string.
|
||||
///
|
||||
std::string getstats (int level=1) const;
|
||||
std::string getstats(int level = 1) const;
|
||||
|
||||
void register_closure (string_view name, int id, const ClosureParam *params,
|
||||
PrepareClosureFunc prepare, SetupClosureFunc setup);
|
||||
void register_closure(string_view name, int id, const ClosureParam* params,
|
||||
PrepareClosureFunc prepare, SetupClosureFunc setup);
|
||||
|
||||
/// Query either by name or id an existing closure. If name is non
|
||||
/// NULL it will use it for the search, otherwise id would be used
|
||||
/// and the name will be placed in name if successful. Also return
|
||||
/// pointer to the params array in the last argument. All args are
|
||||
/// optional but at least one of name or id must non NULL.
|
||||
bool query_closure (const char **name, int *id,
|
||||
const ClosureParam **params);
|
||||
bool query_closure(const char** name, int* id, const ClosureParam** params);
|
||||
|
||||
/// For the proposed shader "global" name, return the corresponding
|
||||
/// SGBits enum.
|
||||
static SGBits globals_bit (ustring name);
|
||||
static SGBits globals_bit(ustring name);
|
||||
|
||||
/// For the SGBits value, return the shader "globals" name.
|
||||
static ustring globals_name (SGBits bit);
|
||||
static ustring globals_name(SGBits bit);
|
||||
|
||||
/// For the proposed raytype name, return the bit pattern that
|
||||
/// describes it, or 0 for an unrecognized name. (This retrieves
|
||||
/// data passed in via attribute("raytypes")).
|
||||
int raytype_bit (ustring name);
|
||||
int raytype_bit(ustring name);
|
||||
|
||||
/// Configure the default raytypes to assume to be on (or off) at optimization
|
||||
/// time for the given group. The raytypes_on gives a bitfield describing which
|
||||
/// ray flags are known to be 1, and raytypes_off describes which ray flags are
|
||||
/// known to be 0. Bits that are not set in either set of flags are not known
|
||||
/// to the optimizer, and will be determined strictly at execution time.
|
||||
void set_raytypes(ShaderGroup *group, int raytypes_on, int raytypes_off);
|
||||
void set_raytypes(ShaderGroup* group, int raytypes_on, int raytypes_off);
|
||||
|
||||
/// Clear any known mappings of symbol locations.
|
||||
void clear_symlocs();
|
||||
@@ -864,31 +913,32 @@ public:
|
||||
|
||||
/// Ensure that the group has been optimized and optionally JITed. The ctx pointer
|
||||
/// supplies a ShadingContext to use.
|
||||
void optimize_group (ShaderGroup *group, ShadingContext *ctx, bool do_jit = true);
|
||||
void optimize_group(ShaderGroup* group, ShadingContext* ctx,
|
||||
bool do_jit = true);
|
||||
|
||||
/// Ensure that the group has been optimized and optionally JITed. This is a
|
||||
/// convenience function that simply calls set_raytypes followed by
|
||||
/// optimize_group. The ctx supplies a ShadingContext to use.
|
||||
void optimize_group (ShaderGroup *group, int raytypes_on,
|
||||
int raytypes_off, ShadingContext *ctx, bool do_jit = true);
|
||||
void optimize_group(ShaderGroup* group, int raytypes_on, int raytypes_off,
|
||||
ShadingContext* ctx, bool do_jit = true);
|
||||
|
||||
/// If option "greedyjit" was set, this call will trigger all
|
||||
/// shader groups that have not yet been compiled to do so with the
|
||||
/// specified number of threads (0 means use all available HW cores).
|
||||
void optimize_all_groups (int nthreads=0, bool do_jit = true);
|
||||
void optimize_all_groups(int nthreads = 0, bool do_jit = true);
|
||||
|
||||
/// Return a pointer to the TextureSystem being used.
|
||||
TextureSystem * texturesys () const;
|
||||
TextureSystem* texturesys() const;
|
||||
|
||||
/// Return a pointer to the RendererServices being used.
|
||||
RendererServices * renderer () const;
|
||||
RendererServices* renderer() const;
|
||||
|
||||
/// Archive the entire shader group so that it can be reconstituted
|
||||
/// later.
|
||||
bool archive_shadergroup (ShaderGroup &group, string_view filename);
|
||||
bool archive_shadergroup(ShaderGroup& group, string_view filename);
|
||||
|
||||
// DEPRECATED(2.0)
|
||||
bool archive_shadergroup (ShaderGroup *group, string_view filename);
|
||||
bool archive_shadergroup(ShaderGroup* group, string_view filename);
|
||||
|
||||
/// Construct and return an OSLQuery initialized with an existing
|
||||
/// ShaderGroup. For a shader group already loaded by the ShadingSystem,
|
||||
@@ -967,9 +1017,8 @@ bool
|
||||
shade_image(ShadingSystem& shadingsys, ShaderGroup& group,
|
||||
const ShaderGlobals* defaultsg, OIIO::ImageBuf& buf,
|
||||
cspan<ustring> outputs,
|
||||
ShadeImageLocations shadelocations = ShadePixelCenters,
|
||||
OIIO::ROI roi = OIIO::ROI(),
|
||||
OIIO::parallel_options popt = 0);
|
||||
ShadeImageLocations shadelocations = ShadePixelCenters,
|
||||
OIIO::ROI roi = OIIO::ROI(), OIIO::parallel_options popt = 0);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+32
-20
@@ -141,6 +141,19 @@ inline OSL_HOSTDEVICE float bits_to_01 (unsigned int bits) {
|
||||
}
|
||||
|
||||
|
||||
OSL_FORCEINLINE OSL_HOSTDEVICE int
|
||||
bitcast_to_uint (float x)
|
||||
{
|
||||
#if OPENIMAGEIO_VERSION >= 20500
|
||||
return OIIO::bitcast<unsigned int, float>(x);
|
||||
#else
|
||||
// obsolete call
|
||||
return OIIO::bit_cast<float, unsigned int>(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef __CUDA_ARCH__
|
||||
// Perform a bjmix (see OpenImageIO/hash.h) on 4 sets of values at once.
|
||||
OSL_FORCEINLINE void
|
||||
@@ -231,7 +244,7 @@ reference_inthash (const unsigned int k[N]) {
|
||||
OSL_FORCEINLINE OSL_HOSTDEVICE unsigned int
|
||||
inthash (const unsigned int k0, const unsigned int k1) {
|
||||
// now hash the data!
|
||||
unsigned int start_val = 0xdeadbeef + (2 << 2) + 13;
|
||||
unsigned int start_val = 0xdeadbeef + (2 << 2) + 13; //NOSONAR
|
||||
|
||||
unsigned int a = start_val + k0;
|
||||
unsigned int b = start_val + k1;
|
||||
@@ -467,7 +480,7 @@ struct HashNoise: public IntHashNoiseBase<HashNoise> {
|
||||
static OSL_FORCEINLINE OSL_HOSTDEVICE unsigned int
|
||||
transformToUint(float val)
|
||||
{
|
||||
return OIIO::bit_cast<float,unsigned int>(val);
|
||||
return bitcast_to_uint(val);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -544,7 +557,6 @@ using PeriodicHashNoise = PeriodicAdaptionOf<HashNoise>;
|
||||
|
||||
|
||||
|
||||
|
||||
inline OSL_HOSTDEVICE int
|
||||
inthashi (int x)
|
||||
{
|
||||
@@ -557,7 +569,7 @@ inline OSL_HOSTDEVICE int
|
||||
inthashf (float x)
|
||||
{
|
||||
return static_cast<int>(
|
||||
inthash(OIIO::bit_cast<float,unsigned int>(x))
|
||||
inthash(bitcast_to_uint(x))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -566,8 +578,8 @@ inthashf (float x, float y)
|
||||
{
|
||||
return static_cast<int>(
|
||||
inthash(
|
||||
OIIO::bit_cast<float,unsigned int>(x),
|
||||
OIIO::bit_cast<float,unsigned int>(y)
|
||||
bitcast_to_uint(x),
|
||||
bitcast_to_uint(y)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -578,9 +590,9 @@ inthashf (const float *x)
|
||||
{
|
||||
return static_cast<int>(
|
||||
inthash(
|
||||
OIIO::bit_cast<float,unsigned int>(x[0]),
|
||||
OIIO::bit_cast<float,unsigned int>(x[1]),
|
||||
OIIO::bit_cast<float,unsigned int>(x[2])
|
||||
bitcast_to_uint(x[0]),
|
||||
bitcast_to_uint(x[1]),
|
||||
bitcast_to_uint(x[2])
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -591,10 +603,10 @@ inthashf (const float *x, float y)
|
||||
{
|
||||
return static_cast<int>(
|
||||
inthash(
|
||||
OIIO::bit_cast<float,unsigned int>(x[0]),
|
||||
OIIO::bit_cast<float,unsigned int>(x[1]),
|
||||
OIIO::bit_cast<float,unsigned int>(x[2]),
|
||||
OIIO::bit_cast<float,unsigned int>(y)
|
||||
bitcast_to_uint(x[0]),
|
||||
bitcast_to_uint(x[1]),
|
||||
bitcast_to_uint(x[2]),
|
||||
bitcast_to_uint(y)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1154,16 +1166,16 @@ private:
|
||||
OSL_FORCEINLINE OSL_HOSTDEVICE HashScalarPeriodic () {}
|
||||
public:
|
||||
OSL_FORCEINLINE OSL_HOSTDEVICE HashScalarPeriodic (float px) {
|
||||
m_px = OIIO::ifloor(px); if (m_px < 1) m_px = 1;
|
||||
m_px = OIIO::ifloor(px); if (m_px < 1) m_px = 1; //NOSONAR
|
||||
}
|
||||
OSL_FORCEINLINE OSL_HOSTDEVICE HashScalarPeriodic (float px, float py) {
|
||||
m_px = OIIO::ifloor(px); if (m_px < 1) m_px = 1;
|
||||
m_py = OIIO::ifloor(py); if (m_py < 1) m_py = 1;
|
||||
m_py = OIIO::ifloor(py); if (m_py < 1) m_py = 1; //NOSONAR
|
||||
}
|
||||
OSL_FORCEINLINE OSL_HOSTDEVICE HashScalarPeriodic (float px, float py, float pz) {
|
||||
m_px = OIIO::ifloor(px); if (m_px < 1) m_px = 1;
|
||||
m_py = OIIO::ifloor(py); if (m_py < 1) m_py = 1;
|
||||
m_pz = OIIO::ifloor(pz); if (m_pz < 1) m_pz = 1;
|
||||
m_pz = OIIO::ifloor(pz); if (m_pz < 1) m_pz = 1; //NOSONAR
|
||||
}
|
||||
OSL_FORCEINLINE OSL_HOSTDEVICE HashScalarPeriodic (float px, float py, float pz, float pw) {
|
||||
m_px = OIIO::ifloor(px); if (m_px < 1) m_px = 1;
|
||||
@@ -1225,16 +1237,16 @@ public:
|
||||
|
||||
struct HashVectorPeriodic {
|
||||
OSL_FORCEINLINE OSL_HOSTDEVICE HashVectorPeriodic (float px) {
|
||||
m_px = OIIO::ifloor(px); if (m_px < 1) m_px = 1;
|
||||
m_px = OIIO::ifloor(px); if (m_px < 1) m_px = 1; //NOSONAR
|
||||
}
|
||||
OSL_FORCEINLINE OSL_HOSTDEVICE HashVectorPeriodic (float px, float py) {
|
||||
m_px = OIIO::ifloor(px); if (m_px < 1) m_px = 1;
|
||||
m_py = OIIO::ifloor(py); if (m_py < 1) m_py = 1;
|
||||
m_py = OIIO::ifloor(py); if (m_py < 1) m_py = 1; //NOSONAR
|
||||
}
|
||||
OSL_FORCEINLINE OSL_HOSTDEVICE HashVectorPeriodic (float px, float py, float pz) {
|
||||
m_px = OIIO::ifloor(px); if (m_px < 1) m_px = 1;
|
||||
m_py = OIIO::ifloor(py); if (m_py < 1) m_py = 1;
|
||||
m_pz = OIIO::ifloor(pz); if (m_pz < 1) m_pz = 1;
|
||||
m_pz = OIIO::ifloor(pz); if (m_pz < 1) m_pz = 1; //NOSONAR
|
||||
}
|
||||
OSL_FORCEINLINE OSL_HOSTDEVICE HashVectorPeriodic (float px, float py, float pz, float pw) {
|
||||
m_px = OIIO::ifloor(px); if (m_px < 1) m_px = 1;
|
||||
@@ -1881,7 +1893,7 @@ OSL_FORCEINLINE OSL_HOSTDEVICE void perlin (Vec3 &result, const H &hash,
|
||||
u, v, w);
|
||||
result = scale3 (result);
|
||||
#else
|
||||
static_assert(std::is_same<Vec3i, decltype(hash(X, Y, Z))>::value, "This re-implementation was developed for Hashs returning a vector type only");
|
||||
static_assert(std::is_same<Vec3i, decltype(hash(X, Y, Z))>::value, "This re-implementation was developed for hashes returning a vector type only");
|
||||
// Want to avoid repeating the same hash work 3 times in a row
|
||||
// so rather than executing the vector version, we will use HashScalar
|
||||
// and directly mask its results on a per component basis
|
||||
|
||||
@@ -61,7 +61,7 @@ class OSOReaderQuery; // Just so OSLQuery can friend OSLReaderQuery
|
||||
/// ~~~
|
||||
///
|
||||
/// And the `Parameter` structure will hold all the information you need
|
||||
/// about that paramter. For example:
|
||||
/// about that parameter. For example:
|
||||
///
|
||||
/// ~~~
|
||||
/// std::cout << "Parameter " << p->name
|
||||
@@ -123,7 +123,7 @@ public:
|
||||
}
|
||||
///< Construct an OSLQuery and open a compiled shader from a disk file.
|
||||
/// The `shadername` may be either the name of the `.oso` file, or the
|
||||
/// name of the shader. The optional `searchpath` paramter gives a
|
||||
/// name of the shader. The optional `searchpath` parameter gives a
|
||||
/// colon-separated list of directories to search for compiled shaders.
|
||||
|
||||
OSL_DEPRECATED("Use ShadingSystem::oslquery(group,layernum)")
|
||||
|
||||
@@ -103,4 +103,7 @@ namespace @PROJ_NAME@ = @PROJ_NAMESPACE_V@;
|
||||
#define __OSL_WIDE_PVT __OSL_CONCAT5(b,__OSL_WIDTH,_,__OSL_TARGET_ISA,_pvt)
|
||||
#endif
|
||||
|
||||
#define __OSL_INDIRECT_STRINGIFY(x) #x
|
||||
#define __OSL_STRINGIFY(x) __OSL_INDIRECT_STRINGIFY(x)
|
||||
|
||||
#endif /* OSLVERSION_H */
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
|
||||
// Tests for MSVS versions, always 0 if not MSVS at all.
|
||||
#if defined(_MSC_VER)
|
||||
# define OSL_MSVS_VERSION _MSC_VER
|
||||
# define OSL_MSVS_AT_LEAST_2013 (_MSC_VER >= 1800)
|
||||
# define OSL_MSVS_BEFORE_2013 (_MSC_VER < 1800)
|
||||
# define OSL_MSVS_AT_LEAST_2015 (_MSC_VER >= 1900)
|
||||
@@ -112,6 +113,7 @@
|
||||
# error "This version of OSL is meant to work only with Visual Studio 2017 or later"
|
||||
# endif
|
||||
#else
|
||||
# define OSL_MSVS_VERSION 0
|
||||
# define OSL_MSVS_AT_LEAST_2013 0
|
||||
# define OSL_MSVS_BEFORE_2013 0
|
||||
# define OSL_MSVS_AT_LEAST_2015 0
|
||||
@@ -263,6 +265,7 @@
|
||||
#endif
|
||||
|
||||
#define OSL_OMP_SIMD_LOOP(...) OSL_OMP_PRAGMA(omp simd __VA_ARGS__)
|
||||
|
||||
#if (OSL_GCCVERSION || OSL_INTEL_CLASSIC_COMPILER_VERSION || OSL_INTEL_LLVM_COMPILER_VERSION)
|
||||
# define OSL_OMP_COMPLEX_SIMD_LOOP(...) OSL_OMP_SIMD_LOOP(__VA_ARGS__)
|
||||
#else
|
||||
@@ -479,11 +482,19 @@
|
||||
# define OSL_DASSERT_MSG(x, ...) ((void)sizeof(x)) /*NOLINT*/
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
|
||||
#define OSL_STACK_ARRAY(TYPE, NAME, DYNAMIC_COUNT) TYPE * NAME = reinterpret_cast<TYPE *>(alloca(sizeof(TYPE)*(DYNAMIC_COUNT)))
|
||||
|
||||
/// OSL_ALLOCA is used to allocate smallish amount of memory on the stack,
|
||||
/// equivalent of C99 type var_name[size].
|
||||
///
|
||||
/// NOTE: in a debug build, this will assert for allocations >= 1MB, which is
|
||||
/// much too big. Hopefully this will keep us from abusing alloca and having
|
||||
/// stack overflows. The rule of thumb is that it's ok to use alloca for small
|
||||
/// things of bounded size, but not for anything that could be arbitrarily
|
||||
/// big, which should instead use heap allocation.
|
||||
#if defined(__GNUC__)
|
||||
# define OSL_ALLOCA(type, size) (assert(size < (1<<20)), (size) != 0 ? (reinterpret_cast<type*>(__builtin_alloca((size) * sizeof(type)))) : nullptr)
|
||||
#else
|
||||
// Utilize variable length array compiler extension when available
|
||||
#define OSL_STACK_ARRAY(TYPE, NAME, DYNAMIC_COUNT) TYPE NAME[DYNAMIC_COUNT]
|
||||
# define OSL_ALLOCA(type, size) (assert(size < (1<<20)), (size) != 0 ? (reinterpret_cast<type*>(alloca((size) * sizeof(type)))) : nullptr)
|
||||
#endif
|
||||
|
||||
OSL_NAMESPACE_ENTER
|
||||
|
||||
@@ -42,6 +42,7 @@ OSL_GCC_PRAGMA(GCC diagnostic ignored "-Wunused-parameter")
|
||||
/// RendererServices defines an abstract interface through which a
|
||||
/// renderer may provide callback to the ShadingSystem.
|
||||
class OSLEXECPUBLIC RendererServices {
|
||||
// Keep interface in sync with rs_free_function.h
|
||||
public:
|
||||
typedef TextureSystem::TextureHandle TextureHandle;
|
||||
typedef TextureSystem::Perthread TexturePerthread;
|
||||
@@ -404,15 +405,6 @@ 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)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
// Copyright Contributors to the Open Shading Language project.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
|
||||
#include <OSL/oslconfig.h>
|
||||
|
||||
// Make all the strings defined in OSL
|
||||
// available to the renderer services free functions
|
||||
OSL_NAMESPACE_ENTER
|
||||
namespace Strings {
|
||||
#define STRDECL(str, var_name) OSLEXECPUBLIC extern const ustring var_name;
|
||||
#include <OSL/strdecls.h>
|
||||
#undef STRDECL
|
||||
}; // namespace Strings
|
||||
OSL_NAMESPACE_EXIT
|
||||
|
||||
#ifdef OSL_HOST_RS_BITCODE
|
||||
extern "C" {
|
||||
# define STRDECL(str, var_name) \
|
||||
const OSL::ustring& RS_##var_name = OSL::Strings::var_name;
|
||||
# include <OSL/strdecls.h>
|
||||
# undef STRDECL
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <OSL/device_string.h>
|
||||
#include <OSL/shaderglobals.h>
|
||||
|
||||
// Prefix for OSL shade op declarations.
|
||||
// "C" linkage (no C++ name mangling) and local visibility
|
||||
#define OSL_RSOP extern "C"
|
||||
|
||||
// We are choosing to use unique names encoding parameters directly
|
||||
// as opposed to using overloaded functions.
|
||||
|
||||
// Keep free functions in sync with virtual function based RendererServices.
|
||||
|
||||
/// Get the 4x4 matrix that transforms by the specified
|
||||
/// transformation at the given time. Return true if ok, false
|
||||
/// on error.
|
||||
OSL_RSOP bool
|
||||
rs_get_matrix_xform_time(OSL::ShaderGlobals* sg, OSL::Matrix44& result,
|
||||
OSL::TransformationPtr from, float time);
|
||||
|
||||
/// Get the 4x4 matrix that transforms by the specified
|
||||
/// transformation at the given time. Return true if ok, false on
|
||||
/// error. Suggested implementation is to use rs_get_matrix_xform_time and
|
||||
/// invert it, but a particular renderer may have a better technique.
|
||||
OSL_RSOP bool
|
||||
rs_get_inverse_matrix_xform_time(OSL::ShaderGlobals* sg, OSL::Matrix44& result,
|
||||
OSL::TransformationPtr xform, float time);
|
||||
|
||||
/// Get the 4x4 matrix that transforms points from the named
|
||||
/// 'from' coordinate system to "common" space at the given time.
|
||||
/// Returns true if ok, false if the named matrix is not known.
|
||||
OSL_RSOP bool
|
||||
rs_get_matrix_space_time(OSL::ShaderGlobals* sg, OSL::Matrix44& result,
|
||||
OSL::StringParam from, float time);
|
||||
|
||||
/// Get the 4x4 matrix that transforms points from "common" space to
|
||||
/// the named 'to' coordinate system to at the given time. Suggested
|
||||
/// implementation is to use rs_get_matrix_space_time and invert it, but a
|
||||
/// particular renderer may have a better technique.
|
||||
OSL_RSOP bool
|
||||
rs_get_inverse_matrix_space_time(OSL::ShaderGlobals* sg, OSL::Matrix44& result,
|
||||
OSL::StringParam to, float time);
|
||||
|
||||
/// Get the 4x4 matrix that transforms by the specified
|
||||
/// transformation. Return true if ok, false on error. Since no
|
||||
/// time value is given, also return false if the transformation may
|
||||
/// be time-varying.
|
||||
OSL_RSOP bool
|
||||
rs_get_matrix_xform(OSL::ShaderGlobals* sg, OSL::Matrix44& result,
|
||||
OSL::TransformationPtr xform);
|
||||
|
||||
/// Get the 4x4 matrix that transforms by the specified
|
||||
/// transformation. Return true if ok, false on error. Since no
|
||||
/// time value is given, also return false if the transformation may
|
||||
/// be time-varying. Suggested implementation is to use
|
||||
/// rs_get_matrix_xform and invert it, but a particular renderer may have a
|
||||
/// better technique.
|
||||
OSL_RSOP bool
|
||||
rs_get_inverse_matrix_xform(OSL::ShaderGlobals* sg, OSL::Matrix44& result,
|
||||
OSL::TransformationPtr xform);
|
||||
|
||||
/// Get the 4x4 matrix that transforms 'from' to "common" space.
|
||||
/// Since there is no time value passed, return false if the
|
||||
/// transformation may be time-varying (as well as if it's not found
|
||||
/// at all).
|
||||
OSL_RSOP bool
|
||||
rs_get_matrix_space(OSL::ShaderGlobals* sg, OSL::Matrix44& result,
|
||||
OSL::StringParam from);
|
||||
|
||||
/// Get the 4x4 matrix that transforms points from "common" space to
|
||||
/// the named 'to' coordinate system. Since there is no time value
|
||||
/// passed, return false if the transformation may be time-varying
|
||||
/// (as well as if it's not found at all). Suggested
|
||||
/// implementation is to use rs_get_matrix_space and invert it, but a
|
||||
/// particular renderer may have a better technique.
|
||||
OSL_RSOP bool
|
||||
rs_get_inverse_matrix_space(OSL::ShaderGlobals* sg, OSL::Matrix44& result,
|
||||
OSL::StringParam to);
|
||||
|
||||
/// Transform points Pin[0..npoints-1] in named coordinate system
|
||||
/// 'from' into 'to' coordinates, storing the result in Pout[] using
|
||||
/// the specified vector semantic (POINT, VECTOR, NORMAL). The
|
||||
/// function returns true if the renderer correctly transformed the
|
||||
/// points, false if it failed (for example, because it did not know
|
||||
/// the name of one of the coordinate systems). Suggested implementation
|
||||
/// is simply to make appropriate calls to rs_get_matrix_space and
|
||||
/// get_inverse_matrix_space. The existence of this function is to allow
|
||||
/// some renderers to provide transformations that cannot be
|
||||
/// expressed by a 4x4 matrix.
|
||||
///
|
||||
/// Note, the virtual function based RendererServices::transform_points
|
||||
/// provides additional functionality/modes that are only used during
|
||||
/// code generation to detect if it required to even call rs_transform_points
|
||||
/// during evaluation of the shader. There is no need for the free
|
||||
/// function version to handle these additional modes.
|
||||
///
|
||||
/// Note to implementations: just return 'false'
|
||||
/// if there isn't a special nonlinear transformation between the
|
||||
/// two spaces.
|
||||
OSL_RSOP bool
|
||||
rs_transform_points(OSL::ShaderGlobals* sg, OSL::StringParam from,
|
||||
OSL::StringParam to, float time, const OSL::Vec3* Pin,
|
||||
OSL::Vec3* Pout, int npoints,
|
||||
OSL::TypeDesc::VECSEMANTICS vectype);
|
||||
@@ -145,7 +145,7 @@ namespace sfm
|
||||
//return static_cast<int>(rintf(x));
|
||||
return rintf(x);
|
||||
#else
|
||||
// emulate rounding by adding/substracting 0.5
|
||||
// emulate rounding by adding/subtracting 0.5
|
||||
return static_cast<int>(x + copysignf(0.5f, x));
|
||||
|
||||
// Other possible factorings
|
||||
@@ -441,7 +441,7 @@ namespace sfm
|
||||
|
||||
// Considering having functionally equivalent versions of Vec3, Color3, Matrix44
|
||||
// with slight modifications to inlining and implementation to avoid aliasing and
|
||||
// improve likelyhood of proper privation of local variables within a SIMD loop
|
||||
// improve likelihood of proper privation of local variables within a SIMD loop
|
||||
|
||||
} // namespace sfm
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ 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
|
||||
@@ -83,6 +86,7 @@ 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.
|
||||
|
||||
+34
-17
@@ -194,17 +194,17 @@ template<int WidthT> struct alignas(WidthT * sizeof(float)) VecReg {
|
||||
};
|
||||
|
||||
static_assert(std::alignment_of<VecReg<16>>::value == 64,
|
||||
"Unexepected alignment");
|
||||
"Unexpected alignment");
|
||||
static_assert(std::alignment_of<VecReg<8>>::value == 32,
|
||||
"Unexepected alignment");
|
||||
"Unexpected alignment");
|
||||
static_assert(std::alignment_of<VecReg<4>>::value == 16,
|
||||
"Unexepected alignment");
|
||||
"Unexpected alignment");
|
||||
static_assert(std::alignment_of<VecReg<16>>::value == VecReg<16>::alignment,
|
||||
"Unexepected alignment");
|
||||
"Unexpected alignment");
|
||||
static_assert(std::alignment_of<VecReg<8>>::value == VecReg<8>::alignment,
|
||||
"Unexepected alignment");
|
||||
"Unexpected alignment");
|
||||
static_assert(std::alignment_of<VecReg<4>>::value == VecReg<4>::alignment,
|
||||
"Unexepected alignment");
|
||||
"Unexpected alignment");
|
||||
|
||||
|
||||
template<typename BuiltinT, int WidthT>
|
||||
@@ -1535,7 +1535,7 @@ assume_aligned(Block<DataT, WidthT>* block_ptr)
|
||||
{
|
||||
static_assert(std::alignment_of<Block<DataT, WidthT>>::value
|
||||
== std::alignment_of<VecReg<WidthT>>::value,
|
||||
"Unexepected alignment");
|
||||
"Unexpected alignment");
|
||||
return assume_aligned<VecReg<WidthT>::alignment>(block_ptr);
|
||||
}
|
||||
|
||||
@@ -1545,7 +1545,7 @@ assume_aligned(const Block<DataT, WidthT>* block_ptr)
|
||||
{
|
||||
static_assert(std::alignment_of<Block<DataT, WidthT>>::value
|
||||
== std::alignment_of<VecReg<WidthT>>::value,
|
||||
"Unexepected alignment");
|
||||
"Unexpected alignment");
|
||||
return assume_aligned<VecReg<WidthT>::alignment>(block_ptr);
|
||||
}
|
||||
|
||||
@@ -2089,7 +2089,7 @@ struct UniformAsWide : public pvt::UniformAsWideImpl<DataT, WidthT> {
|
||||
template<typename DataT>
|
||||
struct WideTraits; // undefined, all types used should be specialized
|
||||
//{
|
||||
//static bool mathes(const TypeDesc &) { return false; }
|
||||
//static bool matches(const TypeDesc &) { return false; }
|
||||
//};
|
||||
|
||||
template<> struct WideTraits<float> {
|
||||
@@ -2128,7 +2128,7 @@ template<> struct WideTraits<ustring> {
|
||||
}
|
||||
};
|
||||
|
||||
// We let Vec3 match any vector semantics as we don't have a seperate Point or Normal classes
|
||||
// We let Vec3 match any vector semantics as we don't have a separate Point or Normal classes
|
||||
template<> struct WideTraits<Vec3> {
|
||||
static bool matches(const TypeDesc& type_desc)
|
||||
{
|
||||
@@ -2229,9 +2229,15 @@ template<typename DataT, int WidthT> struct MaskedLaneProxy {
|
||||
// visibility to end user whose IDE
|
||||
// might display these methods vs. free
|
||||
// functions
|
||||
OSL_FORCEINLINE bool is_on() const { return m_mask.is_on(m_lane); }
|
||||
OSL_FORCEINLINE bool is_on() const
|
||||
{
|
||||
return m_mask.is_on(m_lane);
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE bool is_off() const { return m_mask.is_off(m_lane); }
|
||||
OSL_FORCEINLINE bool is_off() const
|
||||
{
|
||||
return m_mask.is_off(m_lane);
|
||||
}
|
||||
|
||||
private:
|
||||
Block<DataT, WidthT>& m_ref_wide_data;
|
||||
@@ -2293,9 +2299,15 @@ struct MaskedArrayLaneProxy {
|
||||
// visibility to end user whose IDE
|
||||
// might display these methods vs. free
|
||||
// functions
|
||||
OSL_FORCEINLINE bool is_on() const { return m_mask.is_on(m_lane); }
|
||||
OSL_FORCEINLINE bool is_on() const
|
||||
{
|
||||
return m_mask.is_on(m_lane);
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE bool is_off() const { return m_mask.is_off(m_lane); }
|
||||
OSL_FORCEINLINE bool is_off() const
|
||||
{
|
||||
return m_mask.is_off(m_lane);
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE MaskedLaneProxy<DataT, WidthT>
|
||||
operator[](int array_index) const
|
||||
@@ -2727,19 +2739,24 @@ foreach_unique(Wide<DataT, WidthT> wdata, Mask<WidthT> data_mask, FunctorT f)
|
||||
do {
|
||||
ActiveLane lead_lane(remaining_mask.first_on());
|
||||
DataT lead_data = wdata[lead_lane];
|
||||
Mask<WidthT> matching_lanes(false);
|
||||
// Use int instead of Mask<> to allow reduction clause in openmp simd declaration
|
||||
int matching_lanes_bits { 0 };
|
||||
OSL_FORCEINLINE_BLOCK
|
||||
{
|
||||
OSL_OMP_PRAGMA(omp simd simdlen(WidthT))
|
||||
OSL_OMP_PRAGMA(omp simd simdlen(WidthT)
|
||||
reduction(|
|
||||
: matching_lanes_bits))
|
||||
for (int lane = 0; lane < WidthT; ++lane) {
|
||||
// NOTE: the comparison ignores the remaining_mask
|
||||
bool lane_matches = (lead_data == wdata[lane]);
|
||||
// NOTE: using bitwise & to avoid branches
|
||||
if (lane_matches & remaining_mask[lane]) {
|
||||
matching_lanes.set_on(lane);
|
||||
// inline of Mask::set_on(lane)
|
||||
matching_lanes_bits |= 1 << lane;
|
||||
}
|
||||
}
|
||||
}
|
||||
Mask<WidthT> matching_lanes { matching_lanes_bits };
|
||||
|
||||
f(lead_data, matching_lanes);
|
||||
remaining_mask &= ~matching_lanes;
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace __OSL_WIDE_PVT {
|
||||
|
||||
OSL_USING_DATA_WIDTH(__OSL_WIDTH)
|
||||
|
||||
// Foward declaration, implementation is in liboslnoise/wide_gabornoise.h
|
||||
// Forward declaration, implementation is in liboslnoise/wide_gabornoise.h
|
||||
struct DisabledFilterPolicy {
|
||||
static constexpr bool active = false;
|
||||
};
|
||||
@@ -34,7 +34,7 @@ OSL_NOINLINE void
|
||||
wide_gabor(Masked<Dual2<float>> wResult, Wide<const Dual2<float>> wX,
|
||||
NoiseParams const* opt, Block<Vec3>* opt_varying_direction);
|
||||
|
||||
// Foward declaration, implementation is in wide_gabor.h
|
||||
// Forward declaration, implementation is in wide_gabor.h
|
||||
template<int AnisotropicT, typename FilterPolicyT>
|
||||
OSL_NOINLINE void
|
||||
wide_gabor(Masked<Dual2<float>> wResult, Wide<const Dual2<float>> wX,
|
||||
@@ -46,20 +46,20 @@ OSL_NOINLINE void
|
||||
wide_gabor(Masked<Dual2<float>> wResult, Wide<const Dual2<Vec3>> wP,
|
||||
NoiseParams const* opt, Block<Vec3>* opt_varying_direction);
|
||||
|
||||
// Foward declaration, implementation is in wide_gabor.h
|
||||
// Forward declaration, implementation is in wide_gabor.h
|
||||
template<int AnisotropicT, typename FilterPolicyT>
|
||||
OSL_NOINLINE void
|
||||
wide_gabor3(Masked<Dual2<Vec3>> wResult, Wide<const Dual2<float>> wX,
|
||||
NoiseParams const* opt, Block<Vec3>* opt_varying_direction);
|
||||
|
||||
// Foward declaration, implementation is in wide_gabor.h
|
||||
// Forward declaration, implementation is in wide_gabor.h
|
||||
template<int AnisotropicT, typename FilterPolicyT>
|
||||
OSL_NOINLINE void
|
||||
wide_gabor3(Masked<Dual2<Vec3>> wResult, Wide<const Dual2<float>> wX,
|
||||
Wide<const Dual2<float>> wY, NoiseParams const* opt,
|
||||
Block<Vec3>* opt_varying_direction);
|
||||
|
||||
// Foward declaration, implementation is in wide_gabor.h
|
||||
// Forward declaration, implementation is in wide_gabor.h
|
||||
template<int AnisotropicT, typename FilterPolicyT>
|
||||
OSL_NOINLINE void
|
||||
wide_gabor3(Masked<Dual2<Vec3>> wResult, Wide<const Dual2<Vec3>> wP,
|
||||
@@ -71,14 +71,14 @@ wide_gabor3(Masked<Dual2<Vec3>> wResult, Wide<const Dual2<Vec3>> wP,
|
||||
// Periodic gabor(s)
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
// Foward declaration, implementation is in wide_gabor.h
|
||||
// Forward declaration, implementation is in wide_gabor.h
|
||||
template<int AnisotropicT, typename FilterPolicyT>
|
||||
OSL_NOINLINE void
|
||||
wide_pgabor(Masked<Dual2<float>> wResult, Wide<const Dual2<float>> wX,
|
||||
Wide<const float> wXp, NoiseParams const* opt,
|
||||
Block<Vec3>* opt_varying_direction);
|
||||
|
||||
// Foward declaration, implementation is in wide_gabor.h
|
||||
// Forward declaration, implementation is in wide_gabor.h
|
||||
template<int AnisotropicT, typename FilterPolicyT>
|
||||
OSL_NOINLINE void
|
||||
wide_pgabor(Masked<Dual2<float>> wResult, Wide<const Dual2<float>> wX,
|
||||
@@ -86,7 +86,7 @@ wide_pgabor(Masked<Dual2<float>> wResult, Wide<const Dual2<float>> wX,
|
||||
Wide<const float> wYp, NoiseParams const* opt,
|
||||
Block<Vec3>* opt_varying_direction);
|
||||
|
||||
// Foward declaration, implementation is in wide_gabor.h
|
||||
// Forward declaration, implementation is in wide_gabor.h
|
||||
template<int AnisotropicT, typename FilterPolicyT>
|
||||
OSL_NOINLINE void
|
||||
wide_pgabor(Masked<Dual2<float>> wResult, Wide<const Dual2<Vec3>> wP,
|
||||
@@ -95,14 +95,14 @@ wide_pgabor(Masked<Dual2<float>> wResult, Wide<const Dual2<Vec3>> wP,
|
||||
|
||||
|
||||
|
||||
// Foward declaration, implementation is in wide_gabor.h
|
||||
// Forward declaration, implementation is in wide_gabor.h
|
||||
template<int AnisotropicT, typename FilterPolicyT>
|
||||
OSL_NOINLINE void
|
||||
wide_pgabor3(Masked<Dual2<Vec3>> wResult, Wide<const Dual2<float>> wX,
|
||||
Wide<const float> wXp, NoiseParams const* opt,
|
||||
Block<Vec3>* opt_varying_direction);
|
||||
|
||||
// Foward declaration, implementation is in wide_gabor.h
|
||||
// Forward declaration, implementation is in wide_gabor.h
|
||||
template<int AnisotropicT, typename FilterPolicyT>
|
||||
OSL_NOINLINE void
|
||||
wide_pgabor3(Masked<Dual2<Vec3>> wResult, Wide<const Dual2<float>> wX,
|
||||
@@ -110,7 +110,7 @@ wide_pgabor3(Masked<Dual2<Vec3>> wResult, Wide<const Dual2<float>> wX,
|
||||
Wide<const float> wYp, NoiseParams const* opt,
|
||||
Block<Vec3>* opt_varying_direction);
|
||||
|
||||
// Foward declaration, implementation is in wide_gabor.h
|
||||
// Forward declaration, implementation is in wide_gabor.h
|
||||
template<int AnisotropicT, typename FilterPolicyT>
|
||||
OSL_NOINLINE void
|
||||
wide_pgabor3(Masked<Dual2<Vec3>> wResult, Wide<const Dual2<Vec3>> wP,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <OSL/oslconfig.h>
|
||||
#include <OSL/oslversion.h>
|
||||
|
||||
#ifdef OSL_USE_OPTIX
|
||||
@@ -13,14 +14,18 @@
|
||||
# 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
|
||||
@@ -31,14 +36,12 @@ 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;
|
||||
@@ -49,13 +52,19 @@ 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.
|
||||
// OSL::optix::
|
||||
// Mostly under 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."; }
|
||||
};
|
||||
|
||||
+214
-55
@@ -558,7 +558,7 @@ public:
|
||||
///
|
||||
void scope(int s) { m_scope = s; }
|
||||
|
||||
/// Return teh AST node containing the declaration of this symbol.
|
||||
/// Return the AST node containing the declaration of this symbol.
|
||||
/// Use with care!
|
||||
ASTNode* node() const { return m_node; }
|
||||
|
||||
@@ -633,55 +633,133 @@ public:
|
||||
}
|
||||
|
||||
|
||||
void dataoffset(int d) { m_dataoffset = d; }
|
||||
int dataoffset() const { return m_dataoffset; }
|
||||
void dataoffset(int d)
|
||||
{
|
||||
m_dataoffset = d;
|
||||
}
|
||||
int dataoffset() const
|
||||
{
|
||||
return m_dataoffset;
|
||||
}
|
||||
|
||||
void wide_dataoffset(int d) { m_wide_dataoffset = d; }
|
||||
int wide_dataoffset() const { return m_wide_dataoffset; }
|
||||
void wide_dataoffset(int d)
|
||||
{
|
||||
m_wide_dataoffset = d;
|
||||
}
|
||||
int wide_dataoffset() const
|
||||
{
|
||||
return m_wide_dataoffset;
|
||||
}
|
||||
|
||||
SymArena arena() const { return static_cast<SymArena>(m_arena); }
|
||||
SymArena arena() const
|
||||
{
|
||||
return static_cast<SymArena>(m_arena);
|
||||
}
|
||||
|
||||
void initializers(int d) { m_initializers = d; }
|
||||
int initializers() const { return m_initializers; }
|
||||
void initializers(int d)
|
||||
{
|
||||
m_initializers = d;
|
||||
}
|
||||
int initializers() const
|
||||
{
|
||||
return m_initializers;
|
||||
}
|
||||
|
||||
bool has_derivs() const { return m_has_derivs; }
|
||||
void has_derivs(bool new_derivs) { m_has_derivs = new_derivs; }
|
||||
int size() const { return m_size; }
|
||||
void size(size_t newsize) { m_size = (int)newsize; }
|
||||
bool has_derivs() const
|
||||
{
|
||||
return m_has_derivs;
|
||||
}
|
||||
void has_derivs(bool new_derivs)
|
||||
{
|
||||
m_has_derivs = new_derivs;
|
||||
}
|
||||
int size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
void size(size_t newsize)
|
||||
{
|
||||
m_size = (int)newsize;
|
||||
}
|
||||
|
||||
/// Return the size for each point, including derivs.
|
||||
///
|
||||
int derivsize() const { return m_has_derivs ? 3 * m_size : m_size; }
|
||||
int derivsize() const
|
||||
{
|
||||
return m_has_derivs ? 3 * m_size : m_size;
|
||||
}
|
||||
|
||||
bool connected() const { return valuesource() == ConnectedVal; }
|
||||
bool connected_down() const { return m_connected_down; }
|
||||
void connected_down(bool c) { m_connected_down = c; }
|
||||
bool connected() const
|
||||
{
|
||||
return valuesource() == ConnectedVal;
|
||||
}
|
||||
bool connected_down() const
|
||||
{
|
||||
return m_connected_down;
|
||||
}
|
||||
void connected_down(bool c)
|
||||
{
|
||||
m_connected_down = c;
|
||||
}
|
||||
|
||||
/// Where did the symbol's value come from?
|
||||
///
|
||||
enum ValueSource { DefaultVal, InstanceVal, GeomVal, ConnectedVal };
|
||||
|
||||
ValueSource valuesource() const { return (ValueSource)m_valuesource; }
|
||||
void valuesource(ValueSource v) { m_valuesource = v; }
|
||||
ValueSource valuesource() const
|
||||
{
|
||||
return (ValueSource)m_valuesource;
|
||||
}
|
||||
void valuesource(ValueSource v)
|
||||
{
|
||||
m_valuesource = v;
|
||||
}
|
||||
const char* valuesourcename() const;
|
||||
static const char* valuesourcename(ValueSource v);
|
||||
|
||||
int fieldid() const { return m_fieldid; }
|
||||
void fieldid(int id) { m_fieldid = id; }
|
||||
int fieldid() const
|
||||
{
|
||||
return m_fieldid;
|
||||
}
|
||||
void fieldid(int id)
|
||||
{
|
||||
m_fieldid = id;
|
||||
}
|
||||
|
||||
int layer() const { return m_layer; }
|
||||
void layer(int id) { m_layer = id; }
|
||||
int layer() const
|
||||
{
|
||||
return m_layer;
|
||||
}
|
||||
void layer(int id)
|
||||
{
|
||||
m_layer = id;
|
||||
}
|
||||
|
||||
int initbegin() const { return m_initbegin; }
|
||||
void initbegin(int i) { m_initbegin = i; }
|
||||
int initend() const { return m_initend; }
|
||||
void initend(int i) { m_initend = i; }
|
||||
int initbegin() const
|
||||
{
|
||||
return m_initbegin;
|
||||
}
|
||||
void initbegin(int i)
|
||||
{
|
||||
m_initbegin = i;
|
||||
}
|
||||
int initend() const
|
||||
{
|
||||
return m_initend;
|
||||
}
|
||||
void initend(int i)
|
||||
{
|
||||
m_initend = i;
|
||||
}
|
||||
void set_initrange(int b = 0, int e = 0)
|
||||
{
|
||||
m_initbegin = b;
|
||||
m_initend = e;
|
||||
}
|
||||
bool has_init_ops() const { return m_initbegin != m_initend; }
|
||||
bool has_init_ops() const
|
||||
{
|
||||
return m_initbegin != m_initend;
|
||||
}
|
||||
|
||||
/// Clear read/write usage info.
|
||||
///
|
||||
@@ -725,15 +803,42 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
int firstread() const { return m_firstread; }
|
||||
int lastread() const { return m_lastread; }
|
||||
int firstwrite() const { return m_firstwrite; }
|
||||
int lastwrite() const { return m_lastwrite; }
|
||||
int firstuse() const { return std::min(firstread(), firstwrite()); }
|
||||
int lastuse() const { return std::max(lastread(), lastwrite()); }
|
||||
bool everread() const { return lastread() >= 0; }
|
||||
bool everwritten() const { return lastwrite() >= 0; }
|
||||
bool everused() const { return everread() || everwritten(); }
|
||||
int firstread() const
|
||||
{
|
||||
return m_firstread;
|
||||
}
|
||||
int lastread() const
|
||||
{
|
||||
return m_lastread;
|
||||
}
|
||||
int firstwrite() const
|
||||
{
|
||||
return m_firstwrite;
|
||||
}
|
||||
int lastwrite() const
|
||||
{
|
||||
return m_lastwrite;
|
||||
}
|
||||
int firstuse() const
|
||||
{
|
||||
return std::min(firstread(), firstwrite());
|
||||
}
|
||||
int lastuse() const
|
||||
{
|
||||
return std::max(lastread(), lastwrite());
|
||||
}
|
||||
bool everread() const
|
||||
{
|
||||
return lastread() >= 0;
|
||||
}
|
||||
bool everwritten() const
|
||||
{
|
||||
return lastwrite() >= 0;
|
||||
}
|
||||
bool everused() const
|
||||
{
|
||||
return everread() || everwritten();
|
||||
}
|
||||
// everused_in_group is an even more stringent test -- not only must
|
||||
// the symbol not be used within the shader but it also must not be
|
||||
// used elsewhere in the group, by being connected to something downstream
|
||||
@@ -754,31 +859,67 @@ public:
|
||||
m_lastwrite = last;
|
||||
}
|
||||
|
||||
bool initialized() const { return m_initialized; }
|
||||
void initialized(bool init) { m_initialized = init; }
|
||||
bool initialized() const
|
||||
{
|
||||
return m_initialized;
|
||||
}
|
||||
void initialized(bool init)
|
||||
{
|
||||
m_initialized = init;
|
||||
}
|
||||
|
||||
bool lockgeom() const { return m_lockgeom; }
|
||||
void lockgeom(bool lock) { m_lockgeom = lock; }
|
||||
bool lockgeom() const
|
||||
{
|
||||
return m_lockgeom;
|
||||
}
|
||||
void lockgeom(bool lock)
|
||||
{
|
||||
m_lockgeom = lock;
|
||||
}
|
||||
|
||||
bool allowconnect() const { return m_allowconnect; }
|
||||
void allowconnect(bool val) { m_allowconnect = val; }
|
||||
bool allowconnect() const
|
||||
{
|
||||
return m_allowconnect;
|
||||
}
|
||||
void allowconnect(bool val)
|
||||
{
|
||||
m_allowconnect = val;
|
||||
}
|
||||
|
||||
int arraylen() const { return m_typespec.arraylength(); }
|
||||
int arraylen() const
|
||||
{
|
||||
return m_typespec.arraylength();
|
||||
}
|
||||
void arraylen(int len)
|
||||
{
|
||||
m_typespec.make_array(len);
|
||||
m_size = m_typespec.simpletype().size();
|
||||
}
|
||||
|
||||
bool renderer_output() const { return m_renderer_output; }
|
||||
void renderer_output(bool v) { m_renderer_output = v; }
|
||||
bool renderer_output() const
|
||||
{
|
||||
return m_renderer_output;
|
||||
}
|
||||
void renderer_output(bool v)
|
||||
{
|
||||
m_renderer_output = v;
|
||||
}
|
||||
|
||||
// When not uniform a symbol will have a varying value under batched
|
||||
// execution and must use a Wide data type to hold different values
|
||||
// for each data lane executing
|
||||
bool is_uniform() const { return m_is_uniform; }
|
||||
bool is_varying() const { return (m_is_uniform == 0); }
|
||||
void make_varying() { m_is_uniform = false; }
|
||||
bool is_uniform() const
|
||||
{
|
||||
return m_is_uniform;
|
||||
}
|
||||
bool is_varying() const
|
||||
{
|
||||
return (m_is_uniform == 0);
|
||||
}
|
||||
void make_varying()
|
||||
{
|
||||
m_is_uniform = false;
|
||||
}
|
||||
|
||||
// Results of a compare_op and other ops with logically boolean
|
||||
// results under certain conditions could be forced to be represented
|
||||
@@ -792,14 +933,32 @@ public:
|
||||
// The value of forced_llvm_bool() is currently only respected during
|
||||
// batched execution. Forced bools should not be coalesced with regular
|
||||
// ints, only other forced bools.
|
||||
bool forced_llvm_bool() const { return m_forced_llvm_bool; }
|
||||
void forced_llvm_bool(bool v) { m_forced_llvm_bool = v; }
|
||||
bool forced_llvm_bool() const
|
||||
{
|
||||
return m_forced_llvm_bool;
|
||||
}
|
||||
void forced_llvm_bool(bool v)
|
||||
{
|
||||
m_forced_llvm_bool = v;
|
||||
}
|
||||
|
||||
bool readonly() const { return m_readonly; }
|
||||
void readonly(bool v) { m_readonly = v; }
|
||||
bool readonly() const
|
||||
{
|
||||
return m_readonly;
|
||||
}
|
||||
void readonly(bool v)
|
||||
{
|
||||
m_readonly = v;
|
||||
}
|
||||
|
||||
bool is_constant() const { return symtype() == SymTypeConst; }
|
||||
bool is_temp() const { return symtype() == SymTypeTemp; }
|
||||
bool is_constant() const
|
||||
{
|
||||
return symtype() == SymTypeConst;
|
||||
}
|
||||
bool is_temp() const
|
||||
{
|
||||
return symtype() == SymTypeTemp;
|
||||
}
|
||||
|
||||
// Retrieve the const float value (must be a const float!)
|
||||
float get_float(int index = 0) const
|
||||
@@ -855,7 +1014,7 @@ public:
|
||||
|
||||
// Stream output. Note that print/print_vals assume that any string
|
||||
// values are "raw" and they will be converted to C source code "escaped
|
||||
// string" notation for printing. For example, a newline characer will
|
||||
// string" notation for printing. For example, a newline character will
|
||||
// be rendered into the stream as the two character sequence '\n'.
|
||||
std::ostream& print(std::ostream& out, int maxvals = 100000000) const;
|
||||
std::ostream& print_vals(std::ostream& out, int maxvals = 100000000) const;
|
||||
|
||||
+18
-8
@@ -35,7 +35,7 @@ std::atomic<int> node_counts_peak[ASTNode::_last_node];
|
||||
class ScopeExit {
|
||||
public:
|
||||
typedef std::function<void()> Task;
|
||||
explicit ScopeExit(Task&& task) : m_task(std::forward<Task>(task)) {}
|
||||
explicit ScopeExit(Task&& task) : m_task(std::move(task)) {}
|
||||
~ScopeExit() { m_task(); }
|
||||
|
||||
private:
|
||||
@@ -578,8 +578,14 @@ ASTvariable_declaration::ASTvariable_declaration(OSLCompilerImpl* comp,
|
||||
if (symtype == SymTypeLocal && Strutil::starts_with(name, "__debug_tmp__"))
|
||||
symtype = SymTypeTemp;
|
||||
m_sym = new Symbol(name, type, symtype, this);
|
||||
if (!m_ismetadata)
|
||||
if (m_ismetadata) {
|
||||
// Metadata doesn't go in the symbol table, so we need to retain
|
||||
// an owning pointer so it doesn't leak.
|
||||
m_sym_owned.reset(m_sym);
|
||||
} else {
|
||||
// Put in the symbol table, after which symtab is the owner
|
||||
m_compiler->symtab().insert(m_sym);
|
||||
}
|
||||
|
||||
// A struct really makes several subvariables
|
||||
if (type.is_structure() || type.is_structure_array()) {
|
||||
@@ -958,7 +964,8 @@ ASTloop_statement::opname() const
|
||||
|
||||
|
||||
|
||||
const char* ASTloopmod_statement::childname(size_t /*i*/) const
|
||||
const char*
|
||||
ASTloopmod_statement::childname(size_t /*i*/) const
|
||||
{
|
||||
return NULL; // no children
|
||||
}
|
||||
@@ -977,7 +984,8 @@ ASTloopmod_statement::opname() const
|
||||
|
||||
|
||||
|
||||
const char* ASTreturn_statement::childname(size_t /*i*/) const
|
||||
const char*
|
||||
ASTreturn_statement::childname(size_t /*i*/) const
|
||||
{
|
||||
return "expression"; // only child
|
||||
}
|
||||
@@ -993,7 +1001,8 @@ ASTcompound_initializer::ASTcompound_initializer(OSLCompilerImpl* comp,
|
||||
|
||||
|
||||
|
||||
const char* ASTcompound_initializer::childname(size_t /*i*/) const
|
||||
const char*
|
||||
ASTcompound_initializer::childname(size_t /*i*/) const
|
||||
{
|
||||
return canconstruct() ? "args" : "expression_list";
|
||||
}
|
||||
@@ -1116,7 +1125,7 @@ ASTunary_expression::ASTunary_expression (OSLCompilerImpl *comp, int op,
|
||||
: ASTNode (unary_expression_node, comp, op, expr)
|
||||
{
|
||||
// Check for a user-overloaded function for this operator
|
||||
Symbol *sym = comp->symtab().find (ustring::sprintf ("__operator__%s__", opword()));
|
||||
Symbol *sym = comp->symtab().find(ustring::fmtformat("__operator__{}__", opword()));
|
||||
if (sym && sym->symtype() == SymTypeFunction)
|
||||
m_function_overload = (FunctionSymbol *)sym;
|
||||
}
|
||||
@@ -1171,7 +1180,7 @@ ASTbinary_expression::ASTbinary_expression (OSLCompilerImpl *comp, Operator op,
|
||||
// Check for a user-overloaded function for this operator.
|
||||
// Disallow a few ops from overloading.
|
||||
if (op != And && op != Or) {
|
||||
ustring funcname = ustring::sprintf ("__operator__%s__", opword());
|
||||
ustring funcname = ustring::fmtformat("__operator__{}__", opword());
|
||||
Symbol *sym = comp->symtab().find (funcname);
|
||||
if (sym && sym->symtype() == SymTypeFunction)
|
||||
m_function_overload = (FunctionSymbol *)sym;
|
||||
@@ -1340,7 +1349,8 @@ ASTfunction_call::print(std::ostream& out, int indentlevel) const
|
||||
|
||||
|
||||
|
||||
const char* ASTliteral::childname(size_t /*i*/) const
|
||||
const char*
|
||||
ASTliteral::childname(size_t /*i*/) const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+4
-34
@@ -201,37 +201,6 @@ public:
|
||||
|
||||
void sourceline(int line) { m_sourceline = line; }
|
||||
|
||||
template<typename... Args>
|
||||
void errorf(const char* format, const Args&... args) const
|
||||
{
|
||||
OSL_DASSERT(format && format[0]);
|
||||
error_impl(OIIO::Strutil::sprintf(format, args...));
|
||||
}
|
||||
|
||||
/// Warning reporting
|
||||
template<typename... Args>
|
||||
void warningf(const char* format, const Args&... args) const
|
||||
{
|
||||
OSL_DASSERT(format && format[0]);
|
||||
warning_impl(OIIO::Strutil::sprintf(format, args...));
|
||||
}
|
||||
|
||||
/// info reporting
|
||||
template<typename... Args>
|
||||
void infof(const char* format, const Args&... args) const
|
||||
{
|
||||
OSL_DASSERT(format && format[0]);
|
||||
info_impl(OIIO::Strutil::sprintf(format, args...));
|
||||
}
|
||||
|
||||
/// message reporting
|
||||
template<typename... Args>
|
||||
void messagef(const char* format, const Args&... args) const
|
||||
{
|
||||
OSL_DASSERT(format && format[0]);
|
||||
message_impl(OIIO::Strutil::sprintf(format, args...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void errorfmt(const char* format, const Args&... args) const
|
||||
{
|
||||
@@ -406,7 +375,7 @@ protected:
|
||||
void codegen_initlist(ref init, TypeSpec type, Symbol* sym);
|
||||
|
||||
// Special code generation for structure initializers.
|
||||
// It's in the ASTNode base class because it's used from mutiple
|
||||
// It's in the ASTNode base class because it's used from multiple
|
||||
// subclasses.
|
||||
Symbol* codegen_struct_initializers(ref init, Symbol* sym,
|
||||
bool is_constructor = false,
|
||||
@@ -551,7 +520,7 @@ public:
|
||||
|
||||
private:
|
||||
ustring m_name; ///< Name of the symbol (unmangled)
|
||||
Symbol* m_sym; ///< Ptr to the symbol this declares
|
||||
Symbol* m_sym; ///< Ptr to the symbol this declares (non-owning)
|
||||
bool m_isparam; ///< Is this a parameter?
|
||||
bool m_isoutput; ///< Is this an output parameter?
|
||||
bool m_ismetadata; ///< Is this declaration a piece of metadata?
|
||||
@@ -560,6 +529,7 @@ private:
|
||||
// specific initializers.
|
||||
typedef std::pair<ustring, ASTNode*> NamedInit;
|
||||
std::vector<NamedInit> m_struct_field_inits;
|
||||
std::unique_ptr<Symbol> m_sym_owned; // if we own the symbol
|
||||
};
|
||||
|
||||
|
||||
@@ -980,7 +950,7 @@ private:
|
||||
/// return false and call an appropriate error().
|
||||
bool typecheck_printf_args(const char* format, ASTNode* arg);
|
||||
|
||||
/// Handle "funcion calls" that are really struct ctrs.
|
||||
/// Handle "function calls" that are really struct ctrs.
|
||||
TypeSpec typecheck_struct_constructor();
|
||||
|
||||
/// Is the argument number 'arg' read by the op?
|
||||
|
||||
+41
-42
@@ -101,7 +101,7 @@ OSLCompilerImpl::insert_code(int opnum, const char* opname, size_t nargs,
|
||||
Symbol*
|
||||
OSLCompilerImpl::make_temporary(const TypeSpec& type)
|
||||
{
|
||||
ustring name = ustring::sprintf("$tmp%d", ++m_next_temp);
|
||||
ustring name = ustring::fmtformat("$tmp{}", ++m_next_temp);
|
||||
Symbol* s = new Symbol(name, type, SymTypeTemp);
|
||||
symtab().insert(s);
|
||||
|
||||
@@ -131,7 +131,7 @@ OSLCompilerImpl::add_struct_fields(StructSpec* structspec, ustring basename,
|
||||
// arraylen is the length of the array of the surrounding data type
|
||||
for (int i = 0; i < (int)structspec->numfields(); ++i) {
|
||||
const StructSpec::FieldSpec& field(structspec->field(i));
|
||||
ustring fieldname = ustring::sprintf("%s.%s", basename, field.name);
|
||||
ustring fieldname = ustring::fmtformat("{}.{}", basename, field.name);
|
||||
TypeSpec type = field.type;
|
||||
int arr = type.arraylength();
|
||||
if (arr && arraylen) {
|
||||
@@ -175,7 +175,7 @@ OSLCompilerImpl::make_constant(ustring val)
|
||||
return sym;
|
||||
}
|
||||
// It's not a constant we've added before
|
||||
ustring name = ustring::sprintf("$const%d", ++m_next_const);
|
||||
ustring name = ustring::fmtformat("$const{}", ++m_next_const);
|
||||
ConstantSymbol* s = new ConstantSymbol(name, val);
|
||||
symtab().insert(s);
|
||||
m_const_syms.push_back(s);
|
||||
@@ -194,7 +194,7 @@ OSLCompilerImpl::make_constant(TypeDesc type, const void* val)
|
||||
return sym;
|
||||
}
|
||||
// It's not a constant we've added before
|
||||
ustring name = ustring::sprintf("$const%d", ++m_next_const);
|
||||
ustring name = ustring::fmtformat("$const{}", ++m_next_const);
|
||||
ConstantSymbol* s = new ConstantSymbol(name, type);
|
||||
memcpy(s->dataptr(), val, typesize);
|
||||
symtab().insert(s);
|
||||
@@ -212,7 +212,7 @@ OSLCompilerImpl::make_constant(int val)
|
||||
return sym;
|
||||
}
|
||||
// It's not a constant we've added before
|
||||
ustring name = ustring::sprintf("$const%d", ++m_next_const);
|
||||
ustring name = ustring::fmtformat("$const{}", ++m_next_const);
|
||||
ConstantSymbol* s = new ConstantSymbol(name, val);
|
||||
symtab().insert(s);
|
||||
m_const_syms.push_back(s);
|
||||
@@ -229,7 +229,7 @@ OSLCompilerImpl::make_constant(float val)
|
||||
return sym;
|
||||
}
|
||||
// It's not a constant we've added before
|
||||
ustring name = ustring::sprintf("$const%d", ++m_next_const);
|
||||
ustring name = ustring::fmtformat("$const{}", ++m_next_const);
|
||||
ConstantSymbol* s = new ConstantSymbol(name, val);
|
||||
symtab().insert(s);
|
||||
m_const_syms.push_back(s);
|
||||
@@ -247,7 +247,7 @@ OSLCompilerImpl::make_constant(TypeDesc type, float x, float y, float z)
|
||||
return sym;
|
||||
}
|
||||
// It's not a constant we've added before
|
||||
ustring name = ustring::sprintf("$const%d", ++m_next_const);
|
||||
ustring name = ustring::fmtformat("$const{}", ++m_next_const);
|
||||
ConstantSymbol* s = new ConstantSymbol(name, type, x, y, z);
|
||||
symtab().insert(s);
|
||||
m_const_syms.push_back(s);
|
||||
@@ -550,8 +550,8 @@ ASTNode::codegen_assign_struct(StructSpec* structspec, ustring dstsym,
|
||||
// struct within struct -- recurse
|
||||
ustring fieldname(structspec->field(i).name);
|
||||
codegen_assign_struct(fieldtype.structspec(),
|
||||
ustring::sprintf("%s.%s", dstsym, fieldname),
|
||||
ustring::sprintf("%s.%s", srcsym, fieldname),
|
||||
ustring::fmtformat("{}.{}", dstsym, fieldname),
|
||||
ustring::fmtformat("{}.{}", srcsym, fieldname),
|
||||
arrayindex, copywholearrays, 0, paraminit);
|
||||
continue;
|
||||
}
|
||||
@@ -560,8 +560,8 @@ ASTNode::codegen_assign_struct(StructSpec* structspec, ustring dstsym,
|
||||
// struct array within struct -- loop over indices and recurse
|
||||
OSL_ASSERT(!arrayindex && "two levels of arrays not allowed");
|
||||
ustring fieldname(structspec->field(i).name);
|
||||
ustring dstfield = ustring::sprintf("%s.%s", dstsym, fieldname);
|
||||
ustring srcfield = ustring::sprintf("%s.%s", srcsym, fieldname);
|
||||
ustring dstfield = ustring::fmtformat("{}.{}", dstsym, fieldname);
|
||||
ustring srcfield = ustring::fmtformat("{}.{}", srcsym, fieldname);
|
||||
for (int i = 0; i < fieldtype.arraylength(); ++i) {
|
||||
codegen_assign_struct(fieldtype.structspec(), dstfield,
|
||||
srcfield, m_compiler->make_constant(i),
|
||||
@@ -632,16 +632,16 @@ ASTNode::one_default_literal(const Symbol* sym, ASTNode* init, std::string& out,
|
||||
completed = false;
|
||||
} else if (type.is_int()) {
|
||||
if (islit && lit->typespec().is_int())
|
||||
out += Strutil::sprintf("%d", lit->intval());
|
||||
out += fmtformat("{}", lit->intval());
|
||||
else {
|
||||
out += "0"; // FIXME?
|
||||
completed = false;
|
||||
}
|
||||
} else if (type.is_float()) {
|
||||
if (islit && lit->typespec().is_int())
|
||||
out += Strutil::sprintf("%d", lit->intval());
|
||||
out += fmtformat("{}", lit->intval());
|
||||
else if (islit && lit->typespec().is_float())
|
||||
out += Strutil::sprintf("%.9g", lit->floatval());
|
||||
out += fmtformat("{:.9g}", lit->floatval());
|
||||
else {
|
||||
out += "0"; // FIXME?
|
||||
completed = false;
|
||||
@@ -649,10 +649,10 @@ ASTNode::one_default_literal(const Symbol* sym, ASTNode* init, std::string& out,
|
||||
} else if (type.is_triple()) {
|
||||
if (islit && lit->typespec().is_int()) {
|
||||
float f = lit->intval();
|
||||
out += Strutil::sprintf("%.9g%s%.9g%s%.9g", f, sep, f, sep, f);
|
||||
out += fmtformat("{:.9g}{}{:.9g}{}{:.9g}", f, sep, f, sep, f);
|
||||
} else if (islit && lit->typespec().is_float()) {
|
||||
float f = lit->floatval();
|
||||
out += Strutil::sprintf("%.9g%s%.9g%s%.9g", f, sep, f, sep, f);
|
||||
out += fmtformat("{:.9g}{}{:.9g}{}{:.9g}", f, sep, f, sep, f);
|
||||
} else if (init && init->typespec() == type
|
||||
&& (init->nodetype() == ASTNode::type_constructor_node
|
||||
|| (init->nodetype() == ASTNode::compound_initializer_node
|
||||
@@ -682,26 +682,26 @@ ASTNode::one_default_literal(const Symbol* sym, ASTNode* init, std::string& out,
|
||||
}
|
||||
}
|
||||
if (nargs == 1)
|
||||
out += Strutil::sprintf("%.9g%s%.9g%s%.9g", f[0], sep, f[0],
|
||||
sep, f[0]);
|
||||
out += fmtformat("{:.9g}{}{:.9g}{}{:.9g}", f[0], sep, f[0], sep,
|
||||
f[0]);
|
||||
else
|
||||
out += Strutil::sprintf("%.9g%s%.9g%s%.9g", f[0], sep, f[1],
|
||||
sep, f[2]);
|
||||
out += fmtformat("{:.9g}{}{:.9g}{}{:.9g}", f[0], sep, f[1], sep,
|
||||
f[2]);
|
||||
} else {
|
||||
out += Strutil::sprintf("0%s0%s0", sep, sep);
|
||||
out += fmtformat("0{}0{}0", sep, sep);
|
||||
completed = false;
|
||||
}
|
||||
} else if (type.is_matrix()) {
|
||||
if (islit && lit->typespec().is_int()) {
|
||||
float f = lit->intval();
|
||||
for (int c = 0; c < 16; ++c)
|
||||
out += Strutil::sprintf("%.9g%s", (c / 4) == (c % 4) ? f : 0.0f,
|
||||
c < 15 ? sep : "");
|
||||
out += fmtformat("{:.9g}{}", (c / 4) == (c % 4) ? f : 0.0f,
|
||||
c < 15 ? sep : "");
|
||||
} else if (islit && lit->typespec().is_float()) {
|
||||
float f = lit->floatval();
|
||||
for (int c = 0; c < 16; ++c)
|
||||
out += Strutil::sprintf("%.9g%s", (c / 4) == (c % 4) ? f : 0.0f,
|
||||
c < 15 ? sep : "");
|
||||
out += fmtformat("{:.9g}{}", (c / 4) == (c % 4) ? f : 0.0f,
|
||||
c < 15 ? sep : "");
|
||||
} else if (init && init->typespec() == type
|
||||
&& init->nodetype() == ASTNode::type_constructor_node) {
|
||||
ASTtype_constructor* ctr = (ASTtype_constructor*)init;
|
||||
@@ -729,22 +729,21 @@ ASTNode::one_default_literal(const Symbol* sym, ASTNode* init, std::string& out,
|
||||
}
|
||||
if (nargs == 1) {
|
||||
for (int c = 0; c < 16; ++c)
|
||||
out += Strutil::sprintf("%.9g%s",
|
||||
(c / 4) == (c % 4) ? f[0] : 0.0f,
|
||||
c < 15 ? sep : "");
|
||||
out += fmtformat("{:.9g}{}",
|
||||
(c / 4) == (c % 4) ? f[0] : 0.0f,
|
||||
c < 15 ? sep : "");
|
||||
} else {
|
||||
for (int c = 0; c < 16; ++c)
|
||||
out += Strutil::sprintf("%.9g%s", f[c], c < 15 ? sep : "");
|
||||
out += fmtformat("{:.9g}{}", f[c], c < 15 ? sep : "");
|
||||
}
|
||||
} else {
|
||||
for (int c = 0; c < 16; ++c)
|
||||
out += Strutil::sprintf("0%s", c < 15 ? sep : "");
|
||||
out += fmtformat("0{}", c < 15 ? sep : "");
|
||||
completed = false;
|
||||
}
|
||||
} else if (type.is_string()) {
|
||||
if (islit && lit->typespec().is_string())
|
||||
out += Strutil::sprintf("\"%s\"",
|
||||
Strutil::escape_chars(lit->strval()));
|
||||
out += fmtformat("\"{}\"", Strutil::escape_chars(lit->strval()));
|
||||
else {
|
||||
out += "\"\""; // FIXME?
|
||||
completed = false;
|
||||
@@ -903,8 +902,8 @@ ASTNode::codegen_initlist(ref init, TypeSpec type, Symbol* sym)
|
||||
for (int i = 0; init && i < structspec->numfields();
|
||||
init = init->next(), ++i) {
|
||||
const StructSpec::FieldSpec& field(structspec->field(i));
|
||||
ustring fieldname = ustring::sprintf("%s.%s", sym->mangled(),
|
||||
field.name);
|
||||
ustring fieldname = ustring::fmtformat("{}.{}", sym->mangled(),
|
||||
field.name);
|
||||
Symbol* fieldsym = m_compiler->symtab().find_exact(fieldname);
|
||||
if (paraminit) {
|
||||
OSL_DASSERT(nodetype() == variable_declaration_node);
|
||||
@@ -919,7 +918,7 @@ ASTNode::codegen_initlist(ref init, TypeSpec type, Symbol* sym)
|
||||
}
|
||||
|
||||
if (paraminit) {
|
||||
// Warn early about struct array paramters.
|
||||
// Warn early about struct array parameters.
|
||||
// Handling this will likely need changes to oso format.
|
||||
if (type.is_structure_array()) {
|
||||
errorfmt("array of struct are not allowed as parameters");
|
||||
@@ -1073,8 +1072,8 @@ ASTNode::codegen_struct_initializers(ref init, Symbol* sym, bool is_constructor,
|
||||
init = init->next(), ++i) {
|
||||
// Structure element -- assign to the i-th member field
|
||||
const StructSpec::FieldSpec& field(structspec->field(i));
|
||||
ustring fieldname = ustring::sprintf("%s.%s", sym->mangled(),
|
||||
field.name);
|
||||
ustring fieldname = ustring::fmtformat("{}.{}", sym->mangled(),
|
||||
field.name);
|
||||
Symbol* fieldsym = m_compiler->symtab().find_exact(fieldname);
|
||||
if (fieldsym->typespec().is_structure_based()
|
||||
&& (init->nodetype() == type_constructor_node
|
||||
@@ -1240,8 +1239,8 @@ ASTindex::codegen_copy_struct_array_element(StructSpec* structspec,
|
||||
// struct within struct -- recurse!
|
||||
codegen_copy_struct_array_element(
|
||||
type.structspec(),
|
||||
ustring::sprintf("%s.%s", destname, field.name),
|
||||
ustring::sprintf("%s.%s", srcname, field.name), index);
|
||||
ustring::fmtformat("{}.{}", destname, field.name),
|
||||
ustring::fmtformat("{}.{}", srcname, field.name), index);
|
||||
} else {
|
||||
OSL_ASSERT(!type.is_array());
|
||||
Symbol *dfield, *sfield;
|
||||
@@ -1464,7 +1463,7 @@ ASTunary_expression::codegen(Symbol* dest)
|
||||
if (m_function_overload) {
|
||||
// A little crazy, but we temporarily construct an ASTfunction_call
|
||||
// in order to codegen this overloaded operator.
|
||||
ustring funcname = ustring::sprintf("__operator__%s__", opword());
|
||||
ustring funcname = ustring::fmtformat("__operator__{}__", opword());
|
||||
ASTfunction_call fc(m_compiler, funcname, expr().get(),
|
||||
m_function_overload);
|
||||
fc.typecheck(typespec());
|
||||
@@ -2023,8 +2022,8 @@ ASTfunction_call::struct_pair_all_fields(StructSpec* structspec, ustring formal,
|
||||
// struct within struct -- recurse!
|
||||
struct_pair_all_fields(
|
||||
type.structspec(),
|
||||
ustring::sprintf("%s.%s", formal, field.name),
|
||||
ustring::sprintf("%s.%s", actual, field.name), arrayindex);
|
||||
ustring::fmtformat("{}.{}", formal, field.name),
|
||||
ustring::fmtformat("{}.{}", actual, field.name), arrayindex);
|
||||
} else {
|
||||
Symbol *fsym, *asym;
|
||||
m_compiler->struct_field_pair(structspec, fi, formal, actual, fsym,
|
||||
|
||||
@@ -590,7 +590,7 @@ OSLCompilerImpl::write_dependency_file(string_view filename)
|
||||
? stdout
|
||||
: OIIO::Filesystem::fopen(m_deps_filename, "w"));
|
||||
if (depfile) {
|
||||
OIIO::Strutil::fprintf(depfile, "%s: %s", target, filename);
|
||||
OSL::print(depfile, "{}: {}", target, filename);
|
||||
for (const auto& dep : m_file_dependencies) {
|
||||
if (OIIO::Strutil::ends_with(dep, "stdosl.h")
|
||||
&& !m_generate_system_deps)
|
||||
@@ -599,9 +599,9 @@ OSLCompilerImpl::write_dependency_file(string_view filename)
|
||||
continue; // skip pseudo files
|
||||
if (dep == filename)
|
||||
continue; // skip this file, since we already put it first
|
||||
OIIO::Strutil::fprintf(depfile, " \\\n %s", dep);
|
||||
OSL::print(depfile, " \\\n {}", dep);
|
||||
}
|
||||
OIIO::Strutil::fprintf(depfile, "\n");
|
||||
OSL::print(depfile, "\n");
|
||||
if (depfile != stdout)
|
||||
fclose(depfile);
|
||||
} else {
|
||||
@@ -1305,7 +1305,7 @@ OSLCompilerImpl::track_variable_dependencies()
|
||||
// This naivite will never miss a dependency, but it may
|
||||
// overestimate dependencies. (Hence we call this "conservative"
|
||||
// rather than "wrong.") We deem this acceptable for now, since
|
||||
// it's so much easer to implement the conservative dependency
|
||||
// it's so much easier to implement the conservative dependency
|
||||
// analysis, and it's not yet clear that getting it closer to
|
||||
// optimal will have any performance impact on final shaders. Also
|
||||
// because this is probably no worse than the "dependency slop" that
|
||||
|
||||
@@ -75,77 +75,6 @@ public:
|
||||
|
||||
ErrorHandler& errhandler() const { return *m_errhandler; }
|
||||
|
||||
/// Error reporting
|
||||
template<typename... Args>
|
||||
OIIO_DEPRECATED("use errorfmt")
|
||||
void errorf(ustring filename, int line, const char* format,
|
||||
const Args&... args) const
|
||||
{
|
||||
OSL_DASSERT(format && format[0]);
|
||||
std::string msg = OIIO::Strutil::sprintf(format, args...);
|
||||
if (msg.size() && msg.back() == '\n') // trim extra newline
|
||||
msg.pop_back();
|
||||
if (filename.size())
|
||||
m_errhandler->errorfmt("{}:{}: error: {}", filename, line, msg);
|
||||
else
|
||||
m_errhandler->errorfmt("error: {}", msg);
|
||||
m_err = true;
|
||||
}
|
||||
|
||||
/// Warning reporting
|
||||
template<typename... Args>
|
||||
OIIO_DEPRECATED("use warningfmt")
|
||||
void warningf(ustring filename, int line, const char* format,
|
||||
const Args&... args) const
|
||||
{
|
||||
OSL_DASSERT(format && format[0]);
|
||||
if (nowarn(filename, line))
|
||||
return; // skip if the filename/line is on the nowarn list
|
||||
std::string msg = OIIO::Strutil::sprintf(format, args...);
|
||||
if (msg.size() && msg.back() == '\n') // trim extra newline
|
||||
msg.pop_back();
|
||||
if (m_err_on_warning) {
|
||||
errorfmt(filename, line, "{}", msg);
|
||||
return;
|
||||
}
|
||||
if (filename.size())
|
||||
m_errhandler->warningfmt("{}:{}: warning: {}", filename, line, msg);
|
||||
else
|
||||
m_errhandler->warningfmt("warning: {}", msg);
|
||||
}
|
||||
|
||||
/// Info reporting
|
||||
template<typename... Args>
|
||||
OIIO_DEPRECATED("use infofmt")
|
||||
void infof(ustring filename, int line, const char* format,
|
||||
const Args&... args) const
|
||||
{
|
||||
OSL_DASSERT(format && format[0]);
|
||||
std::string msg = OIIO::Strutil::sprintf(format, args...);
|
||||
if (msg.size() && msg.back() == '\n') // trim extra newline
|
||||
msg.pop_back();
|
||||
if (filename.size())
|
||||
m_errhandler->infofmt("{}:{}: info: {}", filename, line, msg);
|
||||
else
|
||||
m_errhandler->infofmt("info: {}", msg);
|
||||
}
|
||||
|
||||
/// message reporting
|
||||
template<typename... Args>
|
||||
OIIO_DEPRECATED("use messagef")
|
||||
void messagef(ustring filename, int line, const char* format,
|
||||
const Args&... args) const
|
||||
{
|
||||
OSL_DASSERT(format && format[0]);
|
||||
std::string msg = OIIO::Strutil::sprintf(format, args...);
|
||||
if (msg.size() && msg.back() == '\n') // trim extra newline
|
||||
msg.pop_back();
|
||||
if (filename.size())
|
||||
m_errhandler->messagefmt("{}:{}: {}", filename, line, msg);
|
||||
else
|
||||
m_errhandler->messagefmt("{}", msg);
|
||||
}
|
||||
|
||||
/// Error reporting
|
||||
template<typename... Args>
|
||||
void errorfmt(ustring filename, int line, const char* format,
|
||||
@@ -461,13 +390,6 @@ private:
|
||||
void write_oso_metadata(const ASTNode* metanode) const;
|
||||
void write_dependency_file(string_view filename);
|
||||
|
||||
template<typename... Args>
|
||||
OSL_DEPRECATED("Use osofmt with std::format conventions")
|
||||
inline void osof(const char* fmt, const Args&... args) const
|
||||
{
|
||||
(*m_osofile) << OIIO::Strutil::sprintf(fmt, args...);
|
||||
}
|
||||
|
||||
// Output text to the osofile, using std::format formatting conventions.
|
||||
template<typename... Args>
|
||||
inline void osofmt(const char* fmt, const Args&... args) const
|
||||
@@ -568,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, ustringHash> FCMap;
|
||||
typedef std::unordered_map<ustring, std::string> 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
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
#pragma clang diagnostic ignored "-Wparentheses-equality"
|
||||
#endif
|
||||
|
||||
#if (OSL_CLANG_VERSION >= 150000) || (OSL_INTEL_CLANG_VERSION >= 140000)
|
||||
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC visibility push(hidden)
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
/** Lexical scanner for Open Shading Language
|
||||
**/
|
||||
|
||||
%top{
|
||||
/* Include this first to avoid warnings about re-definitions on windows */
|
||||
#include <stdint.h>
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
* Definitions section
|
||||
************************************************************/
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace pvt { // OSL::pvt
|
||||
std::string
|
||||
Symbol::mangled() const
|
||||
{
|
||||
std::string result = scope() ? Strutil::sprintf("___%d_%s", scope(), m_name)
|
||||
std::string result = scope() ? fmtformat("___{}_{}", scope(), m_name)
|
||||
: m_name.string();
|
||||
return result; // Force NRVO (named value return optimization)
|
||||
}
|
||||
@@ -54,8 +54,7 @@ Symbol::symtype_shortname(SymType s)
|
||||
std::string
|
||||
StructSpec::mangled() const
|
||||
{
|
||||
return scope() ? Strutil::sprintf("___%d_%s", scope(), m_name)
|
||||
: m_name.string();
|
||||
return scope() ? fmtformat("___{}_{}", scope(), m_name) : m_name.string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ private:
|
||||
///
|
||||
class SymbolTable {
|
||||
public:
|
||||
typedef std::unordered_map<ustring, Symbol*, ustringHash> ScopeTable;
|
||||
typedef std::unordered_map<ustring, Symbol*> ScopeTable;
|
||||
typedef std::vector<ScopeTable> ScopeTableStack;
|
||||
typedef SymbolPtrVec::iterator iterator;
|
||||
typedef SymbolPtrVec::const_iterator const_iterator;
|
||||
|
||||
+134
-120
@@ -65,7 +65,8 @@ ASTfunction_declaration::typecheck(TypeSpec expected)
|
||||
|
||||
|
||||
|
||||
TypeSpec ASTvariable_declaration::typecheck(TypeSpec /*expected*/)
|
||||
TypeSpec
|
||||
ASTvariable_declaration::typecheck(TypeSpec /*expected*/)
|
||||
{
|
||||
typecheck_children(m_typespec);
|
||||
ASTNode* init = this->init().get();
|
||||
@@ -79,7 +80,7 @@ TypeSpec ASTvariable_declaration::typecheck(TypeSpec /*expected*/)
|
||||
if (m_typespec.is_structure() && !m_initlist
|
||||
&& et.structure() != vt.structure()) {
|
||||
// Can't do: struct foo = 1
|
||||
errorf("Cannot initialize %s %s = %s", vt, name(), et);
|
||||
errorfmt("Cannot initialize {} {} = {}", vt, name(), et);
|
||||
return m_typespec;
|
||||
}
|
||||
|
||||
@@ -88,7 +89,7 @@ TypeSpec ASTvariable_declaration::typecheck(TypeSpec /*expected*/)
|
||||
// typecheck method.
|
||||
if (init->nodetype() == compound_initializer_node) {
|
||||
if (init->nextptr())
|
||||
errorf("compound_initializer should be the only initializer");
|
||||
errorfmt("compound_initializer should be the only initializer");
|
||||
init = ((ASTcompound_initializer*)init)->initlist().get();
|
||||
if (!init)
|
||||
return m_typespec;
|
||||
@@ -106,10 +107,10 @@ TypeSpec ASTvariable_declaration::typecheck(TypeSpec /*expected*/)
|
||||
if (!assignable(vt, et)) {
|
||||
// Special case: for int=float, it's just a warning.
|
||||
if (vt.is_int() && et.is_float())
|
||||
warningf("Assignment may lose precision: %s %s = %s", vt, name(),
|
||||
et);
|
||||
warningfmt("Assignment may lose precision: {} {} = {}", vt, name(),
|
||||
et);
|
||||
else
|
||||
errorf("Cannot assign %s %s = %s", vt, name(), et);
|
||||
errorfmt("Cannot assign {} {} = {}", vt, name(), et);
|
||||
return m_typespec;
|
||||
}
|
||||
|
||||
@@ -118,7 +119,8 @@ TypeSpec ASTvariable_declaration::typecheck(TypeSpec /*expected*/)
|
||||
|
||||
|
||||
|
||||
TypeSpec ASTvariable_ref::typecheck(TypeSpec /*expected*/)
|
||||
TypeSpec
|
||||
ASTvariable_ref::typecheck(TypeSpec /*expected*/)
|
||||
{
|
||||
m_is_lvalue = true; // A var ref is an lvalue
|
||||
return m_typespec;
|
||||
@@ -126,7 +128,8 @@ TypeSpec ASTvariable_ref::typecheck(TypeSpec /*expected*/)
|
||||
|
||||
|
||||
|
||||
TypeSpec ASTpreincdec::typecheck(TypeSpec /*expected*/)
|
||||
TypeSpec
|
||||
ASTpreincdec::typecheck(TypeSpec /*expected*/)
|
||||
{
|
||||
typecheck_children();
|
||||
m_is_lvalue = var()->is_lvalue();
|
||||
@@ -136,11 +139,12 @@ TypeSpec ASTpreincdec::typecheck(TypeSpec /*expected*/)
|
||||
|
||||
|
||||
|
||||
TypeSpec ASTpostincdec::typecheck(TypeSpec /*expected*/)
|
||||
TypeSpec
|
||||
ASTpostincdec::typecheck(TypeSpec /*expected*/)
|
||||
{
|
||||
typecheck_children();
|
||||
if (!var()->is_lvalue())
|
||||
errorf("%s can only be applied to an lvalue", nodetypename());
|
||||
errorfmt("{} can only be applied to an lvalue", nodetypename());
|
||||
m_is_lvalue = false;
|
||||
m_typespec = var()->typespec();
|
||||
return m_typespec;
|
||||
@@ -148,29 +152,30 @@ TypeSpec ASTpostincdec::typecheck(TypeSpec /*expected*/)
|
||||
|
||||
|
||||
|
||||
TypeSpec ASTindex::typecheck(TypeSpec /*expected*/)
|
||||
TypeSpec
|
||||
ASTindex::typecheck(TypeSpec /*expected*/)
|
||||
{
|
||||
typecheck_children();
|
||||
const char* indextype = "";
|
||||
TypeSpec t = lvalue()->typespec();
|
||||
if (t.is_structure()) {
|
||||
errorf("Cannot use [] indexing on a struct");
|
||||
errorfmt("Cannot use [] indexing on a struct");
|
||||
return TypeSpec();
|
||||
}
|
||||
if (t.is_closure()) {
|
||||
errorf("Cannot use [] indexing on a closure");
|
||||
errorfmt("Cannot use [] indexing on a closure");
|
||||
return TypeSpec();
|
||||
}
|
||||
if (index3()) {
|
||||
if (!t.is_array() && !t.elementtype().is_matrix())
|
||||
errorf("[][][] only valid for a matrix array");
|
||||
errorfmt("[][][] only valid for a matrix array");
|
||||
m_typespec = TypeDesc::FLOAT;
|
||||
} else if (t.is_array()) {
|
||||
indextype = "array";
|
||||
m_typespec = t.elementtype();
|
||||
if (index2()) {
|
||||
if (t.aggregate() == TypeDesc::SCALAR)
|
||||
errorf("can't use [][] on a simple array");
|
||||
errorfmt("can't use [][] on a simple array");
|
||||
m_typespec = TypeDesc::FLOAT;
|
||||
}
|
||||
} else if (t.aggregate() == TypeDesc::VEC3) {
|
||||
@@ -180,7 +185,7 @@ TypeSpec ASTindex::typecheck(TypeSpec /*expected*/)
|
||||
tnew.vecsemantics = TypeDesc::NOXFORM;
|
||||
m_typespec = tnew;
|
||||
if (index2())
|
||||
errorf("can't use [][] on a %s", t);
|
||||
errorfmt("can't use [][] on a {}", t);
|
||||
} else if (t.aggregate() == TypeDesc::MATRIX44) {
|
||||
indextype = "component";
|
||||
TypeDesc tnew = t.simpletype();
|
||||
@@ -188,17 +193,18 @@ TypeSpec ASTindex::typecheck(TypeSpec /*expected*/)
|
||||
tnew.vecsemantics = TypeDesc::NOXFORM;
|
||||
m_typespec = tnew;
|
||||
if (!index2())
|
||||
errorf("must use [][] on a matrix, not just []");
|
||||
errorfmt("must use [][] on a matrix, not just []");
|
||||
} else {
|
||||
errorf("can only use [] indexing for arrays or multi-component types");
|
||||
errorfmt(
|
||||
"can only use [] indexing for arrays or multi-component types");
|
||||
return TypeSpec();
|
||||
}
|
||||
|
||||
// Make sure the indices (children 1+) are integers
|
||||
for (size_t c = 1; c < nchildren(); ++c)
|
||||
if (!child(c)->typespec().is_int())
|
||||
errorf("%s index must be an integer, not a %s", indextype,
|
||||
index()->typespec());
|
||||
errorfmt("{} index must be an integer, not a {}", indextype,
|
||||
index()->typespec());
|
||||
|
||||
// If the thing we're indexing is an lvalue, so is the indexed element
|
||||
m_is_lvalue = lvalue()->is_lvalue();
|
||||
@@ -230,7 +236,8 @@ ASTstructselect::typecheck(TypeSpec expected)
|
||||
|
||||
|
||||
|
||||
TypeSpec ASTconditional_statement::typecheck(TypeSpec /*expected*/)
|
||||
TypeSpec
|
||||
ASTconditional_statement::typecheck(TypeSpec /*expected*/)
|
||||
{
|
||||
typecheck_list(cond());
|
||||
m_compiler->push_nesting(false);
|
||||
@@ -240,15 +247,16 @@ TypeSpec ASTconditional_statement::typecheck(TypeSpec /*expected*/)
|
||||
|
||||
TypeSpec c = cond()->typespec();
|
||||
if (c.is_structure())
|
||||
errorf("Cannot use a struct as an 'if' condition");
|
||||
errorfmt("Cannot use a struct as an 'if' condition");
|
||||
if (c.is_array())
|
||||
errorf("Cannot use an array as an 'if' condition");
|
||||
errorfmt("Cannot use an array as an 'if' condition");
|
||||
return m_typespec = TypeDesc(TypeDesc::NONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TypeSpec ASTloop_statement::typecheck(TypeSpec /*expected*/)
|
||||
TypeSpec
|
||||
ASTloop_statement::typecheck(TypeSpec /*expected*/)
|
||||
{
|
||||
typecheck_list(init());
|
||||
m_compiler->push_nesting(true);
|
||||
@@ -259,34 +267,36 @@ TypeSpec ASTloop_statement::typecheck(TypeSpec /*expected*/)
|
||||
|
||||
TypeSpec c = cond()->typespec();
|
||||
if (c.is_closure())
|
||||
errorf("Cannot use a closure as an '%s' condition", opname());
|
||||
errorfmt("Cannot use a closure as an '{}' condition", opname());
|
||||
if (c.is_structure())
|
||||
errorf("Cannot use a struct as an '%s' condition", opname());
|
||||
errorfmt("Cannot use a struct as an '{}' condition", opname());
|
||||
if (c.is_array())
|
||||
errorf("Cannot use an array as an '%s' condition", opname());
|
||||
errorfmt("Cannot use an array as an '{}' condition", opname());
|
||||
return m_typespec = TypeDesc(TypeDesc::NONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TypeSpec ASTloopmod_statement::typecheck(TypeSpec /*expected*/)
|
||||
TypeSpec
|
||||
ASTloopmod_statement::typecheck(TypeSpec /*expected*/)
|
||||
{
|
||||
if (m_compiler->nesting_level(true /*loops*/) < 1)
|
||||
errorf("Cannot '%s' here -- not inside a loop.", opname());
|
||||
errorfmt("Cannot '{}' here -- not inside a loop.", opname());
|
||||
return m_typespec = TypeDesc(TypeDesc::NONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TypeSpec ASTassign_expression::typecheck(TypeSpec /*expected*/)
|
||||
TypeSpec
|
||||
ASTassign_expression::typecheck(TypeSpec /*expected*/)
|
||||
{
|
||||
TypeSpec vt = var()->typecheck(); // Type of the variable
|
||||
TypeSpec et = expr()->typecheck(vt); // Type of the expression assigned
|
||||
m_typespec = vt;
|
||||
|
||||
if (!var()->is_lvalue()) {
|
||||
errorf("Can't assign via %s to something that isn't an lvalue",
|
||||
opname());
|
||||
errorfmt("Can't assign via {} to something that isn't an lvalue",
|
||||
opname());
|
||||
return TypeSpec();
|
||||
}
|
||||
|
||||
@@ -307,7 +317,7 @@ TypeSpec ASTassign_expression::typecheck(TypeSpec /*expected*/)
|
||||
return m_typespec;
|
||||
}
|
||||
}
|
||||
errorf("Cannot assign %s %s = %s", vt, varname, et);
|
||||
errorfmt("Cannot assign {} {} = {}", vt, varname, et);
|
||||
return m_typespec;
|
||||
}
|
||||
|
||||
@@ -326,7 +336,7 @@ TypeSpec ASTassign_expression::typecheck(TypeSpec /*expected*/)
|
||||
if (vts == ets)
|
||||
return m_typespec = vt;
|
||||
// Otherwise, a structure mismatch
|
||||
errorf("Cannot assign %s %s = %s", vt, varname, et);
|
||||
errorfmt("Cannot assign {} {} = {}", vt, varname, et);
|
||||
return m_typespec;
|
||||
}
|
||||
|
||||
@@ -334,10 +344,10 @@ TypeSpec ASTassign_expression::typecheck(TypeSpec /*expected*/)
|
||||
if (!assignable(vt, et)) {
|
||||
// Special case: for int=float, it's just a warning.
|
||||
if (vt.is_int() && et.is_float())
|
||||
warningf("Assignment may lose precision: %s %s = %s", vt, varname,
|
||||
et);
|
||||
warningfmt("Assignment may lose precision: {} {} = {}", vt, varname,
|
||||
et);
|
||||
else
|
||||
errorf("Cannot assign %s %s = %s", vt, varname, et);
|
||||
errorfmt("Cannot assign {} {} = {}", vt, varname, et);
|
||||
return m_typespec;
|
||||
}
|
||||
|
||||
@@ -346,7 +356,8 @@ TypeSpec ASTassign_expression::typecheck(TypeSpec /*expected*/)
|
||||
|
||||
|
||||
|
||||
TypeSpec ASTreturn_statement::typecheck(TypeSpec /*expected*/)
|
||||
TypeSpec
|
||||
ASTreturn_statement::typecheck(TypeSpec /*expected*/)
|
||||
{
|
||||
FunctionSymbol* myfunc = m_compiler->current_function();
|
||||
if (myfunc) {
|
||||
@@ -357,14 +368,14 @@ TypeSpec ASTreturn_statement::typecheck(TypeSpec /*expected*/)
|
||||
// will also catch returning a value from a void function.
|
||||
TypeSpec et = expr()->typecheck(myfunc->typespec());
|
||||
if (!assignable(myfunc->typespec(), et)) {
|
||||
errorf("Cannot return a '%s' from '%s %s()'", et,
|
||||
myfunc->typespec(), myfunc->name());
|
||||
errorfmt("Cannot return a '{}' from '{} {}()'", et,
|
||||
myfunc->typespec(), myfunc->name());
|
||||
}
|
||||
} else {
|
||||
// If we are not returning a value, it must be a void function.
|
||||
if (!myfunc->typespec().is_void())
|
||||
errorf("You must return a '%s' from function '%s'",
|
||||
myfunc->typespec(), myfunc->name());
|
||||
errorfmt("You must return a '{}' from function '{}'",
|
||||
myfunc->typespec(), myfunc->name());
|
||||
}
|
||||
myfunc->encountered_return();
|
||||
} else {
|
||||
@@ -372,7 +383,7 @@ TypeSpec ASTreturn_statement::typecheck(TypeSpec /*expected*/)
|
||||
// be from the main shader body. That's fine (it's equivalent
|
||||
// to calling exit()), but it can't return a value.
|
||||
if (expr())
|
||||
errorf("Cannot return a value from a shader body");
|
||||
errorfmt("Cannot return a value from a shader body");
|
||||
}
|
||||
return TypeSpec(); // TODO: what should be returned here?
|
||||
}
|
||||
@@ -402,14 +413,14 @@ ASTunary_expression::typecheck(TypeSpec expected)
|
||||
}
|
||||
|
||||
if (t.is_structure() || t.is_array()) {
|
||||
errorf("Can't do '%s' to a %s.", opname(), t);
|
||||
errorfmt("Can't do '{}' to a {}.", opname(), t);
|
||||
return TypeSpec();
|
||||
}
|
||||
switch (m_op) {
|
||||
case Sub:
|
||||
case Add:
|
||||
if (!(t.is_closure() || t.is_numeric())) {
|
||||
errorf("Can't do '%s' to a %s.", opname(), t);
|
||||
errorfmt("Can't do '{}' to a {}.", opname(), t);
|
||||
return TypeSpec();
|
||||
}
|
||||
m_typespec = t;
|
||||
@@ -419,12 +430,12 @@ ASTunary_expression::typecheck(TypeSpec expected)
|
||||
break;
|
||||
case Compl:
|
||||
if (!t.is_int()) {
|
||||
errorf("Operator '~' can only be done to an int");
|
||||
errorfmt("Operator '~' can only be done to an int");
|
||||
return TypeSpec();
|
||||
}
|
||||
m_typespec = t;
|
||||
break;
|
||||
default: errorf("unknown unary operator");
|
||||
default: errorfmt("unknown unary operator");
|
||||
}
|
||||
return m_typespec;
|
||||
}
|
||||
@@ -467,7 +478,7 @@ ASTbinary_expression::typecheck(TypeSpec expected)
|
||||
TypeSpec returntype = m_compiler->type_from_code(code, &advance);
|
||||
code += advance;
|
||||
if (code[0] && check_simple_arg(l, code, true) && code[0]
|
||||
&& check_simple_arg(r, code, true) && !code[0]) {
|
||||
&& check_simple_arg(r, code, true) && !code[0]) { // NOSONAR
|
||||
return m_typespec = returntype;
|
||||
}
|
||||
}
|
||||
@@ -477,7 +488,7 @@ ASTbinary_expression::typecheck(TypeSpec expected)
|
||||
|
||||
// No binary ops work on structs or arrays
|
||||
if (l.is_structure() || r.is_structure() || l.is_array() || r.is_array()) {
|
||||
errorf("Not allowed: '%s %s %s'", l, opname(), r);
|
||||
errorfmt("Not allowed: '{} {} {}'", l, opname(), r);
|
||||
return TypeSpec();
|
||||
}
|
||||
|
||||
@@ -507,7 +518,7 @@ ASTbinary_expression::typecheck(TypeSpec expected)
|
||||
return m_typespec = TypeDesc::TypeInt;
|
||||
}
|
||||
// If we got this far, it's an op that's not allowed
|
||||
errorf("Not allowed: '%s %s %s'", l, opname(), r);
|
||||
errorfmt("Not allowed: '{} {} {}'", l, opname(), r);
|
||||
return TypeSpec();
|
||||
}
|
||||
|
||||
@@ -581,11 +592,11 @@ ASTbinary_expression::typecheck(TypeSpec expected)
|
||||
// nonzeroness), but always return int.
|
||||
return m_typespec = TypeDesc::TypeInt;
|
||||
|
||||
default: errorf("unknown binary operator");
|
||||
default: errorfmt("unknown binary operator");
|
||||
}
|
||||
|
||||
// If we got this far, it's an op that's not allowed
|
||||
errorf("Not allowed: '%s %s %s'", l, opname(), r);
|
||||
errorfmt("Not allowed: '{} {} {}'", l, opname(), r);
|
||||
return TypeSpec();
|
||||
}
|
||||
|
||||
@@ -600,15 +611,15 @@ ASTternary_expression::typecheck(TypeSpec expected)
|
||||
TypeSpec f = typecheck_list(falseexpr(), expected);
|
||||
|
||||
if (c.is_closure())
|
||||
errorf("Cannot use a closure as a condition");
|
||||
errorfmt("Cannot use a closure as a condition");
|
||||
if (c.is_structure())
|
||||
errorf("Cannot use a struct as a condition");
|
||||
errorfmt("Cannot use a struct as a condition");
|
||||
if (c.is_array())
|
||||
errorf("Cannot use an array as a condition");
|
||||
errorfmt("Cannot use an array as a condition");
|
||||
|
||||
// No arrays
|
||||
if (t.is_array() || t.is_array()) {
|
||||
errorf("Not allowed: '%s ? %s : %s'", c, t, f);
|
||||
if (t.is_array() || f.is_array()) {
|
||||
errorfmt("Not allowed: '{} ? {} : {}'", c, t, f);
|
||||
return TypeSpec();
|
||||
}
|
||||
|
||||
@@ -617,7 +628,7 @@ ASTternary_expression::typecheck(TypeSpec expected)
|
||||
if (assignable(t, f) || assignable(f, t))
|
||||
m_typespec = higherprecision(t.simpletype(), f.simpletype());
|
||||
else
|
||||
errorf("Not allowed: '%s ? %s : %s'", c, t, f);
|
||||
errorfmt("Not allowed: '{} ? {} : {}'", c, t, f);
|
||||
|
||||
return m_typespec;
|
||||
}
|
||||
@@ -634,7 +645,8 @@ ASTcomma_operator::typecheck(TypeSpec expected)
|
||||
|
||||
|
||||
|
||||
TypeSpec ASTtypecast_expression::typecheck(TypeSpec /*expected*/)
|
||||
TypeSpec
|
||||
ASTtypecast_expression::typecheck(TypeSpec /*expected*/)
|
||||
{
|
||||
// FIXME - closures
|
||||
typecheck_children(m_typespec);
|
||||
@@ -642,7 +654,7 @@ TypeSpec ASTtypecast_expression::typecheck(TypeSpec /*expected*/)
|
||||
if (!assignable(m_typespec, t) && !(m_typespec.is_int() && t.is_float())
|
||||
&& // (int)float is ok
|
||||
!(m_typespec.is_triple() && t.is_triple()))
|
||||
errorf("Cannot cast '%s' to '%s'", t, m_typespec);
|
||||
errorfmt("Cannot cast '{}' to '{}'", t, m_typespec);
|
||||
return m_typespec;
|
||||
}
|
||||
|
||||
@@ -666,7 +678,7 @@ ASTtype_constructor::typecheck(TypeSpec expected, bool report, bool bind)
|
||||
if (expected.is_float()) {
|
||||
patterns = float_patterns;
|
||||
argexpected = TypeDesc::FLOAT;
|
||||
// ^^^ Since simetimes tht constructor `float(expr)` is used as a
|
||||
// ^^^ Since sometimes the constructor `float(expr)` is used as a
|
||||
// synonym for a cast `(float)expr`, we know that ambiguously typed
|
||||
// expressions should favor disambiguating to a float.
|
||||
} else if (expected.is_triple()) {
|
||||
@@ -686,7 +698,7 @@ ASTtype_constructor::typecheck(TypeSpec expected, bool report, bool bind)
|
||||
patterns = int_patterns;
|
||||
} else {
|
||||
if (report)
|
||||
errorf("Cannot construct type '%s'", expected);
|
||||
errorfmt("Cannot construct type '{}'", expected);
|
||||
return TypeSpec();
|
||||
}
|
||||
|
||||
@@ -706,15 +718,15 @@ ASTtype_constructor::typecheck(TypeSpec expected, bool report, bool bind)
|
||||
|
||||
// If we made it this far, no match could be found.
|
||||
if (report) {
|
||||
std::string err = OIIO::Strutil::sprintf("Cannot construct %s (",
|
||||
expected);
|
||||
std::string err = OIIO::Strutil::fmt::format("Cannot construct {} (",
|
||||
expected);
|
||||
for (ref a = args(); a; a = a->next()) {
|
||||
err += a->typespec().string();
|
||||
if (a->next())
|
||||
err += ", ";
|
||||
}
|
||||
err += ")";
|
||||
errorf("%s", err);
|
||||
errorfmt("{}", err);
|
||||
// FIXME -- it might be nice here to enumerate for the user all the
|
||||
// valid combinations.
|
||||
}
|
||||
@@ -750,7 +762,7 @@ public:
|
||||
|
||||
~TypeAdjuster()
|
||||
{
|
||||
// Commit infered types of all ASTcompound_initializers scanned.
|
||||
// Commit inferred types of all ASTcompound_initializers scanned.
|
||||
if (m_success) {
|
||||
for (auto&& initer : m_adjust) {
|
||||
ASTcompound_initializer* ciptr = std::get<0>(initer);
|
||||
@@ -775,9 +787,9 @@ public:
|
||||
if (m_mode & must_init_all) {
|
||||
m_success = false;
|
||||
if (errors()) {
|
||||
cinit->errorf("Empty initializer list not allowed to"
|
||||
"represent '%' here",
|
||||
to);
|
||||
cinit->errorfmt("Empty initializer list not allowed to "
|
||||
"represent '{}' here",
|
||||
to);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -840,9 +852,9 @@ public:
|
||||
|
||||
m_success = false;
|
||||
if (errors()) {
|
||||
init->errorf("Too %s initializers for a '%s'",
|
||||
nelem < expected.arraylength() ? "few" : "many",
|
||||
expected);
|
||||
init->errorfmt("Too {} initializers for a '{}'",
|
||||
nelem < expected.arraylength() ? "few" : "many",
|
||||
expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -888,9 +900,9 @@ public:
|
||||
|
||||
m_success = false;
|
||||
if (errors() && (arg || nfields > ninits)) {
|
||||
parent->errorf("Too %s initializers for struct '%s'",
|
||||
ninits < nfields ? "few" : "many",
|
||||
structspec->name());
|
||||
parent->errorfmt("Too {} initializers for struct '{}'",
|
||||
ninits < nfields ? "few" : "many",
|
||||
structspec->name());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -980,9 +992,9 @@ private:
|
||||
const StructSpec::FieldSpec* field = nullptr)
|
||||
{
|
||||
if (node->typecheck(expected) != expected &&
|
||||
// Alllow assignment with comparable type
|
||||
// Allow assignment with comparable type
|
||||
!assignable(expected, node->typespec()) &&
|
||||
// Alllow closure assignments to '0'
|
||||
// Allow closure assignments to '0'
|
||||
!(expected.is_closure() && !node->typespec().is_closure()
|
||||
&& node->typespec().is_int_or_float()
|
||||
&& node->nodetype() == literal_node
|
||||
@@ -992,11 +1004,11 @@ private:
|
||||
return false;
|
||||
|
||||
OSL_DASSERT(!spec || field);
|
||||
node->errorf("Can't assign '%s' to '%s%s'", node->typespec(),
|
||||
expected,
|
||||
!spec ? ""
|
||||
: Strutil::sprintf(" %s.%s", spec->name(),
|
||||
field->name));
|
||||
node->errorfmt("Can't assign '{}' to '{}{}'", node->typespec(),
|
||||
expected,
|
||||
!spec ? ""
|
||||
: Strutil::fmt::format(" {}.{}", spec->name(),
|
||||
field->name));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1010,7 +1022,7 @@ ASTcompound_initializer::typecheck(TypeSpec expected, unsigned mode)
|
||||
if (m_ctor || m_typespec.is_structure_based()
|
||||
|| m_typespec.simpletype().basetype != TypeDesc::UNKNOWN) {
|
||||
if (m_typespec != expected)
|
||||
errorf("Cannot construct type '%s'", expected);
|
||||
errorfmt("Cannot construct type '{}'", expected);
|
||||
return m_typespec;
|
||||
}
|
||||
|
||||
@@ -1053,6 +1065,8 @@ bool
|
||||
ASTNode::check_arglist(const char* /*funcname*/, ASTNode::ref arg,
|
||||
const char* formals, bool coerce, bool bind)
|
||||
{
|
||||
if (!formals)
|
||||
return false;
|
||||
// std::cerr << "ca " << funcname << " formals='" << formals << "\n";
|
||||
for (; arg; arg = arg->next()) {
|
||||
if (!*formals) // More formal args, but no more actual args
|
||||
@@ -1188,14 +1202,14 @@ ASTfunction_call::typecheck_printf_args(const char* format, ASTNode* arg)
|
||||
++format;
|
||||
char formatchar = *format++; // Also eat the format char
|
||||
if (!arg) {
|
||||
errorf(
|
||||
"%s has mismatched format string and arguments (not enough args)",
|
||||
errorfmt(
|
||||
"{} has mismatched format string and arguments (not enough args)",
|
||||
m_name);
|
||||
return false;
|
||||
}
|
||||
if (arg->typespec().is_structure_based()) {
|
||||
errorf("struct '%s' is not a valid argument",
|
||||
arg->typespec().structspec()->name());
|
||||
errorfmt("struct '{}' is not a valid argument",
|
||||
arg->typespec().structspec()->name());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1205,16 +1219,16 @@ ASTfunction_call::typecheck_printf_args(const char* format, ASTNode* arg)
|
||||
if ((arg->typespec().is_closure_based()
|
||||
|| simpletype.basetype == TypeDesc::STRING)
|
||||
&& formatchar != 's') {
|
||||
errorf(
|
||||
"%s has mismatched format string and arguments (arg %d needs %%s)",
|
||||
errorfmt(
|
||||
"{} has mismatched format string and arguments (arg {} needs %s)",
|
||||
m_name);
|
||||
return false;
|
||||
}
|
||||
if (simpletype.basetype == TypeDesc::INT && formatchar != 'd'
|
||||
&& formatchar != 'i' && formatchar != 'o' && formatchar != 'x'
|
||||
&& formatchar != 'X') {
|
||||
errorf(
|
||||
"%s has mismatched format string and arguments (arg %d needs %%d, %%i, %%o, %%x, or %%X)",
|
||||
errorfmt(
|
||||
"{} has mismatched format string and arguments (arg {} needs %d, %i, %o, %x, or %X)",
|
||||
m_name, argnum);
|
||||
return false;
|
||||
}
|
||||
@@ -1222,8 +1236,8 @@ ASTfunction_call::typecheck_printf_args(const char* format, ASTNode* arg)
|
||||
&& formatchar != 'g' && formatchar != 'c' && formatchar != 'e'
|
||||
&& formatchar != 'm' && formatchar != 'n' && formatchar != 'p'
|
||||
&& formatchar != 'v') {
|
||||
errorf(
|
||||
"%s has mismatched format string and arguments (arg %d needs %%f, %%g, or %%e)",
|
||||
errorfmt(
|
||||
"{} has mismatched format string and arguments (arg {} needs %f, %g, or %e)",
|
||||
m_name, argnum);
|
||||
return false;
|
||||
}
|
||||
@@ -1236,8 +1250,8 @@ ASTfunction_call::typecheck_printf_args(const char* format, ASTNode* arg)
|
||||
}
|
||||
}
|
||||
if (arg) {
|
||||
errorf("%s has mismatched format string and arguments (too many args)",
|
||||
m_name);
|
||||
errorfmt("{} has mismatched format string and arguments (too many args)",
|
||||
m_name);
|
||||
return false;
|
||||
}
|
||||
return true; // all ok
|
||||
@@ -1303,8 +1317,8 @@ ASTfunction_call::typecheck_builtin_specialcase()
|
||||
arg = arg->nextptr();
|
||||
typecheck_printf_args(format, arg);
|
||||
} else {
|
||||
warningf("%s() uses a format string that is not a constant.",
|
||||
m_name);
|
||||
warningfmt("{}() uses a format string that is not a constant.",
|
||||
m_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1379,8 +1393,8 @@ ASTfunction_call::typecheck_struct_constructor()
|
||||
m_typespec = m_sym->typespec();
|
||||
if (structspec->numfields() != (int)listlength(args())) {
|
||||
// Support a single argument which is an init-list of proper type?
|
||||
errorf(
|
||||
"Constructor for '%s' has the wrong number of arguments (expected %d, got %d)",
|
||||
errorfmt(
|
||||
"Constructor for '{}' has the wrong number of arguments (expected {}, got {})",
|
||||
structspec->name(), structspec->numfields(), listlength(args()));
|
||||
}
|
||||
|
||||
@@ -1607,7 +1621,7 @@ class CandidateFunctions {
|
||||
|
||||
default:
|
||||
// TODO: Scoring default function arguments would go here
|
||||
// Curently an unused formal argument, so no match at all.
|
||||
// Currently an unused formal argument, so no match at all.
|
||||
return kNoMatch;
|
||||
}
|
||||
OSL_DASSERT(*formals == 0);
|
||||
@@ -1672,8 +1686,8 @@ public:
|
||||
comma = ", ";
|
||||
}
|
||||
argstr += ")";
|
||||
return Strutil::sprintf("%s '%s'%s\n", msg, argstr,
|
||||
candidateMsg ? "\n Candidates are:" : "");
|
||||
return Strutil::fmt::format("{} '{}'{}\n", msg, argstr,
|
||||
candidateMsg ? "\n Candidates are:" : "");
|
||||
}
|
||||
|
||||
std::string reportFunction(FunctionSymbol* sym) const
|
||||
@@ -1684,10 +1698,10 @@ public:
|
||||
formals += advance;
|
||||
std::string msg = " ";
|
||||
if (ASTNode* decl = sym->node())
|
||||
msg += Strutil::sprintf("%s:%d\t", decl->sourcefile(),
|
||||
decl->sourceline());
|
||||
msg += Strutil::sprintf("%s %s (%s)\n", returntype, sym->name(),
|
||||
m_compiler->typelist_from_code(formals));
|
||||
msg += Strutil::fmt::format("{}:{}\t", decl->sourcefile(),
|
||||
decl->sourceline());
|
||||
msg += Strutil::fmt::format("{} {} ({})\n", returntype, sym->name(),
|
||||
m_compiler->typelist_from_code(formals));
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -1715,7 +1729,7 @@ public:
|
||||
"No matching function call to");
|
||||
for (FunctionSymbol* f = m_called; f; f = f->nextpoly())
|
||||
errmsg += reportFunction(f);
|
||||
caller->errorf("%s", errmsg);
|
||||
caller->errorfmt("{}", errmsg);
|
||||
return { nullptr, TypeSpec() };
|
||||
|
||||
case 1: // Success
|
||||
@@ -1840,17 +1854,17 @@ public:
|
||||
= reportAmbiguity(funcname, !warn /* "Candidates are" msg*/,
|
||||
"Ambiguous call to");
|
||||
if (warn) {
|
||||
errmsg += Strutil::sprintf(" Chosen function is:\n%s",
|
||||
reportFunction(c.first->sym));
|
||||
errmsg += Strutil::fmt::format(" Chosen function is:\n{}",
|
||||
reportFunction(c.first->sym));
|
||||
errmsg += " Other candidates are:\n";
|
||||
for (auto& candidate : m_candidates)
|
||||
if (candidate.sym != c.first->sym)
|
||||
errmsg += reportFunction(candidate.sym);
|
||||
caller->warningf("%s", errmsg);
|
||||
caller->warningfmt("{}", errmsg);
|
||||
} else {
|
||||
for (auto& candidate : m_candidates)
|
||||
errmsg += reportFunction(candidate.sym);
|
||||
caller->errorf("%s", errmsg);
|
||||
caller->errorfmt("{}", errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1982,7 +1996,7 @@ ASTfunction_call::typecheck(TypeSpec expected)
|
||||
any_args_are_compound_initializers = true;
|
||||
}
|
||||
|
||||
// Save the currently choosen symbol for error reporting later
|
||||
// Save the currently chosen symbol for error reporting later
|
||||
FunctionSymbol* poly = func();
|
||||
|
||||
CandidateFunctions candidates(m_compiler, expected, args(), poly);
|
||||
@@ -2013,9 +2027,9 @@ ASTfunction_call::typecheck(TypeSpec expected)
|
||||
if (Strutil::iequals(OSL_LEGACY, "use"))
|
||||
m_sym = legacy;
|
||||
if (as_warning)
|
||||
warningf("overload chosen differs from OSL 1.9\n%s", errmsg);
|
||||
warningfmt("overload chosen differs from OSL 1.9\n{}", errmsg);
|
||||
else
|
||||
errorf("overload chosen differs from OSL 1.9\n%s", errmsg);
|
||||
errorfmt("overload chosen differs from OSL 1.9\n{}", errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2053,8 +2067,8 @@ ASTfunction_call::typecheck(TypeSpec expected)
|
||||
if (formal->is_output()
|
||||
&& !check_symbol_writeability(a, true, &dest_sym)) {
|
||||
OSL_DASSERT(dest_sym);
|
||||
warningf(
|
||||
"cannot write to non-output parameter \"%s\", as passed to function %s() as arg %d (output parameter \"%s\")",
|
||||
warningfmt(
|
||||
"cannot write to non-output parameter \"{}\", as passed to function {}() as arg {} (output parameter \"{}\")",
|
||||
dest_sym->name(), func()->name(), i + 1, formal->name());
|
||||
}
|
||||
}
|
||||
@@ -2062,8 +2076,8 @@ ASTfunction_call::typecheck(TypeSpec expected)
|
||||
|
||||
if (is_user_function()) {
|
||||
if (func()->number_of_returns() == 0 && !func()->typespec().is_void()) {
|
||||
errorf("non-void function \"%s\" had no 'return' statement.",
|
||||
func()->name());
|
||||
errorfmt("non-void function \"{}\" had no 'return' statement.",
|
||||
func()->name());
|
||||
}
|
||||
} else {
|
||||
// built-in
|
||||
@@ -2318,7 +2332,7 @@ OSLCompilerImpl::code_from_type(TypeSpec type) const
|
||||
std::string out;
|
||||
TypeDesc elem = type.elementtype().simpletype();
|
||||
if (type.is_structure() || type.is_structure_array()) {
|
||||
out = Strutil::sprintf("S%d", type.structure());
|
||||
out = Strutil::fmt::format("S{}", type.structure());
|
||||
} else if (type.is_closure() || type.is_closure_array()) {
|
||||
out = 'C';
|
||||
} else {
|
||||
@@ -2352,7 +2366,7 @@ OSLCompilerImpl::code_from_type(TypeSpec type) const
|
||||
if (type.is_unsized_array())
|
||||
out += "[]";
|
||||
else
|
||||
out += Strutil::sprintf("[%d]", type.arraylength());
|
||||
out += Strutil::fmt::format("[{}]", type.arraylength());
|
||||
}
|
||||
|
||||
return out;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
set ( liboslexec_target_srcs
|
||||
wide/wide_opalgebraic
|
||||
wide/wide_opcolor
|
||||
wide/wide_opclosure
|
||||
wide/wide_opdictionary
|
||||
wide/wide_ophash
|
||||
wide/wide_opmatrix
|
||||
@@ -120,6 +121,7 @@ set (lib_src
|
||||
shadeimage.cpp
|
||||
backendllvm.cpp
|
||||
llvm_gen.cpp llvm_instance.cpp llvm_util.cpp
|
||||
rs_fallback.cpp
|
||||
)
|
||||
if (BUILD_BATCHED)
|
||||
list(APPEND lib_src
|
||||
@@ -179,94 +181,6 @@ foreach(src ${lib_src})
|
||||
endif()
|
||||
endforeach(src)
|
||||
|
||||
macro ( LLVM_COMPILE llvm_src srclist )
|
||||
get_filename_component ( llvmsrc_we ${llvm_src} NAME_WE )
|
||||
set ( llvm_asm "${CMAKE_CURRENT_BINARY_DIR}/${llvmsrc_we}.s" )
|
||||
set ( llvm_bc "${CMAKE_CURRENT_BINARY_DIR}/${llvmsrc_we}.bc" )
|
||||
set ( llvm_bc_cpp "${CMAKE_CURRENT_BINARY_DIR}/${llvmsrc_we}.bc.cpp" )
|
||||
if (VERBOSE)
|
||||
message (STATUS "LLVM_COMPILE in=${llvm_src}")
|
||||
message (STATUS "LLVM_COMPILE asm=${llvm_asm}")
|
||||
message (STATUS "LLVM_COMPILE bc=${llvm_bc}")
|
||||
message (STATUS "LLVM_COMPILE cpp=${llvm_bc_cpp}")
|
||||
endif ()
|
||||
set ( ${srclist} ${${srclist}} ${llvm_bc_cpp} )
|
||||
get_property (CURRENT_DEFINITIONS DIRECTORY PROPERTY COMPILE_DEFINITIONS)
|
||||
if (VERBOSE)
|
||||
message (STATUS "Current #defines are ${CURRENT_DEFINITIONS}")
|
||||
endif ()
|
||||
foreach (def ${CURRENT_DEFINITIONS})
|
||||
set (LLVM_COMPILE_FLAGS ${LLVM_COMPILE_FLAGS} "-D${def}")
|
||||
endforeach()
|
||||
set (LLVM_COMPILE_FLAGS ${LLVM_COMPILE_FLAGS} ${SIMD_COMPILE_FLAGS} ${CSTD_FLAGS} ${TOOLCHAIN_FLAGS})
|
||||
|
||||
# Figure out what program we will use to make the bitcode.
|
||||
if (NOT LLVM_BC_GENERATOR)
|
||||
find_program (LLVM_BC_GENERATOR NAMES "clang++"
|
||||
PATHS "${LLVM_DIRECTORY}/bin"
|
||||
NO_CMAKE_PATH NO_DEFAULT_PATH NO_CMAKE_SYSTEM_PATH
|
||||
NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_ENVIRONMENT_PATH)
|
||||
endif ()
|
||||
# If that didn't work, look anywhere
|
||||
if (NOT LLVM_BC_GENERATOR)
|
||||
# Wasn't in their build, look anywhere
|
||||
find_program (LLVM_BC_GENERATOR NAMES clang++ llvm-g++)
|
||||
endif ()
|
||||
|
||||
if (NOT LLVM_BC_GENERATOR)
|
||||
message (FATAL_ERROR "You must have a valid llvm bitcode generator (clang++) somewhere.")
|
||||
endif ()
|
||||
if (VERBOSE)
|
||||
message (STATUS "Using LLVM_BC_GENERATOR ${LLVM_BC_GENERATOR} to generate bitcode.")
|
||||
endif()
|
||||
|
||||
# Fix specific problem I had on new Apple systems (e.g. Mavericks) with
|
||||
# LLVM/libc++ installed -- for some reason, LLVM 3.4 wasn't finding it,
|
||||
# so in that specific case, append another -I to point it in the right
|
||||
# direction.
|
||||
#if (APPLE AND ${LLVM_BC_GENERATOR} MATCHES ".*clang.*")
|
||||
# exec_program ( "${LLVM_BC_GENERATOR}" ARGS --version OUTPUT_VARIABLE MY_CLANG_VERSION )
|
||||
# string (REGEX REPLACE "clang version ([0-9][.][0-9]+).*" "\\1" MY_CLANG_VERSION "${MY_CLANG_VERSION}")
|
||||
# if ((${MY_CLANG_VERSION} VERSION_GREATER "3.3")
|
||||
# AND (EXISTS "/usr/lib/libc++.dylib")
|
||||
# AND (EXISTS "/Library/Developer/CommandLineTools/usr/lib/c++/v1"))
|
||||
# set (LLVM_COMPILE_FLAGS ${LLVM_COMPILE_FLAGS} "-I/Library/Developer/CommandLineTools/usr/lib/c++/v1")
|
||||
# endif ()
|
||||
#endif ()
|
||||
|
||||
list (TRANSFORM IMATH_INCLUDES PREPEND -I
|
||||
OUTPUT_VARIABLE ALL_IMATH_INCLUDES)
|
||||
list (TRANSFORM OPENEXR_INCLUDES PREPEND -I
|
||||
OUTPUT_VARIABLE ALL_OPENEXR_INCLUDES)
|
||||
list (TRANSFORM OpenImageIO_INCLUDES PREPEND -I
|
||||
OUTPUT_VARIABLE ALL_OpenImageIO_INCLUDES)
|
||||
|
||||
# Command to turn the .cpp file into LLVM assembly language .s, into
|
||||
# LLVM bitcode .bc, then back into a C++ file with the bc embedded!
|
||||
add_custom_command ( OUTPUT ${llvm_bc_cpp}
|
||||
COMMAND ${LLVM_BC_GENERATOR}
|
||||
${LLVM_COMPILE_FLAGS}
|
||||
"-I${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"-I${CMAKE_SOURCE_DIR}/src/include"
|
||||
"-I${CMAKE_BINARY_DIR}/include"
|
||||
${ALL_OpenImageIO_INCLUDES}
|
||||
${ALL_IMATH_INCLUDES}
|
||||
"-isystem ${Boost_INCLUDE_DIRS}"
|
||||
-DOSL_COMPILING_TO_BITCODE=1
|
||||
-Wno-deprecated-register
|
||||
# the following 2 warnings can be restored when all 3rd parties have fixed their export macros
|
||||
# (dllimport attribute is not supported when compiling for Cuda and triggers a ton of warnings)
|
||||
-Wno-ignored-attributes -Wno-unknown-attributes
|
||||
-O3 -fno-math-errno -S -emit-llvm -o ${llvm_asm} ${llvm_src}
|
||||
COMMAND "${LLVM_DIRECTORY}/bin/llvm-as" -f -o ${llvm_bc} ${llvm_asm}
|
||||
COMMAND python "${CMAKE_CURRENT_SOURCE_DIR}/serialize-bc.py" ${llvm_bc} ${llvm_bc_cpp} "osl_llvm_compiled_ops"
|
||||
MAIN_DEPENDENCY ${llvm_src}
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/serialize-bc.py"
|
||||
${exec_headers} ${PROJECT_PUBLIC_HEADERS}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
endmacro ( )
|
||||
|
||||
|
||||
macro ( CUDA_SHADEOPS_COMPILE srclist )
|
||||
# Add all of the "shadeops" sources that need to be compiled to LLVM bitcode for CUDA
|
||||
set ( shadeops_srcs
|
||||
@@ -291,21 +205,31 @@ macro ( CUDA_SHADEOPS_COMPILE srclist )
|
||||
|
||||
# Link all of the individual LLVM bitcode files
|
||||
add_custom_command ( OUTPUT ${linked_shadeops_bc}
|
||||
COMMAND "${LLVM_DIRECTORY}/bin/llvm-link" -internalize ${shadeops_bc_list} -o ${linked_shadeops_bc}
|
||||
COMMAND ${LLVM_LINK_TOOL} -internalize ${shadeops_bc_list} -o ${linked_shadeops_bc}
|
||||
DEPENDS ${shadeops_bc_list} ${exec_headers} ${PROJECT_PUBLIC_HEADERS} ${shadeops_srcs}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
|
||||
# Serialize the linked bitcode into a CPP file and add it to the list of liboslexec soures
|
||||
# Serialize the linked bitcode into a CPP file and add it to the list of liboslexec sources
|
||||
add_custom_command ( OUTPUT ${shadeops_bc_cuda_cpp}
|
||||
COMMAND python "${CMAKE_CURRENT_SOURCE_DIR}/serialize-bc.py"
|
||||
COMMAND ${Python_EXECUTABLE} "${CMAKE_SOURCE_DIR}/src/build-scripts/serialize-bc.py"
|
||||
${linked_shadeops_bc} ${shadeops_bc_cuda_cpp} "osl_llvm_compiled_ops_cuda"
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/serialize-bc.py" ${linked_shadeops_bc}
|
||||
DEPENDS "${CMAKE_SOURCE_DIR}/src/build-scripts/serialize-bc.py" ${linked_shadeops_bc}
|
||||
${exec_headers} ${PROJECT_PUBLIC_HEADERS}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
endmacro ( )
|
||||
|
||||
if (USE_LLVM_BITCODE)
|
||||
LLVM_COMPILE ( llvm_ops.cpp lib_src )
|
||||
set (llvm_ops_srcs llvm_ops.cpp)
|
||||
EMBED_LLVM_BITCODE_IN_CPP ( "${llvm_ops_srcs}" "_host" "osl_llvm_compiled_ops" lib_src "")
|
||||
|
||||
set (rs_dependent_ops_srcs
|
||||
opmatrix.cpp
|
||||
)
|
||||
# Achieve the effect of absorbing osl_llvm_compiled_ops by adding its
|
||||
# sources to rs_dependent_ops_srcs which avoids having to do it at runtime.
|
||||
list (APPEND rs_dependent_ops_srcs ${llvm_ops_srcs})
|
||||
|
||||
EMBED_LLVM_BITCODE_IN_CPP ( "${rs_dependent_ops_srcs}" "_host_rs" "osl_llvm_compiled_rs_dependent_ops" lib_src "")
|
||||
|
||||
# Optionally repeat the bitcode compilation with CUDA-specific options
|
||||
if (CUDA_FOUND)
|
||||
@@ -428,7 +352,7 @@ foreach(batched_target ${BATCHED_TARGET_LIST})
|
||||
endif ()
|
||||
|
||||
if (CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_APPLECLANG)
|
||||
# REQUIRES CLANG 7+ to use sucessfully vectorize with OpenMP simd
|
||||
# REQUIRES CLANG 7+ to use successfully vectorize with OpenMP simd
|
||||
|
||||
if (${TARGET_OPT_ISA} STREQUAL "AVX512")
|
||||
list (APPEND TARGET_CXX_OPTS "-march=skylake-avx512")
|
||||
@@ -446,7 +370,13 @@ foreach(batched_target ${BATCHED_TARGET_LIST})
|
||||
endif ()
|
||||
|
||||
if (${TARGET_OPT_FMA} STREQUAL "noFMA")
|
||||
list (APPEND TARGET_CXX_OPTS "-mno-fma")
|
||||
# Do NOT use "-mno-fma" as it may lower ISA to one without any FMA
|
||||
# instructions (AVX512->AVX2). Our intent is to not generate
|
||||
# FMA's but still use the available instructions and register
|
||||
# width. However math library calls may use still end up using
|
||||
# FMA's, but lets try turning of fused math ops because many OSL
|
||||
# math functions are from OIIO/IMath headers generate non FMA
|
||||
list (APPEND TARGET_CXX_OPTS "-ffp-contract=off")
|
||||
endif ()
|
||||
|
||||
# large SIMD function loops will exceed llvm's -inline-threshold default of 225.
|
||||
@@ -464,7 +394,8 @@ foreach(batched_target ${BATCHED_TARGET_LIST})
|
||||
list (APPEND TARGET_CXX_OPTS "-fno-unroll-loops")
|
||||
|
||||
if (CMAKE_COMPILER_IS_INTELCLANG)
|
||||
list (APPEND TARGET_CXX_OPTS "-qopenmp-simd")
|
||||
# utilize Intel compiler's optimized openmp simd generation vs. open source "-qopenmp-simd"
|
||||
list (APPEND TARGET_CXX_OPTS "-fiopenmp-simd")
|
||||
else ()
|
||||
list (APPEND TARGET_CXX_OPTS "-fopenmp")
|
||||
endif ()
|
||||
@@ -510,7 +441,13 @@ foreach(batched_target ${BATCHED_TARGET_LIST})
|
||||
endif ()
|
||||
|
||||
if (${TARGET_OPT_FMA} STREQUAL "noFMA")
|
||||
list (APPEND TARGET_CXX_OPTS "-mno-fma")
|
||||
# Do NOT use "-mno-fma" as it may lower ISA to one without any FMA
|
||||
# instructions (AVX512->AVX2). Our intent is to not generate
|
||||
# FMA's but still use the available instructions and register
|
||||
# width. However math library calls may use still end up using
|
||||
# FMA's, but lets try turning of fused math ops because many OSL
|
||||
# math functions are from OIIO/IMath headers generate non FMA
|
||||
list (APPEND TARGET_CXX_OPTS "-ffp-contract=off")
|
||||
endif ()
|
||||
|
||||
list (APPEND TARGET_CXX_OPTS "-fopenmp-simd")
|
||||
|
||||
+28
-26
@@ -12,7 +12,7 @@ OSL_NAMESPACE_ENTER
|
||||
|
||||
|
||||
void
|
||||
AovOutput::flush(void *flush_data)
|
||||
AovOutput::flush(void* flush_data)
|
||||
{
|
||||
if (!aov)
|
||||
return;
|
||||
@@ -21,7 +21,7 @@ AovOutput::flush(void *flush_data)
|
||||
has_color = true;
|
||||
}
|
||||
if (neg_alpha) {
|
||||
alpha = 1.0f - alpha;
|
||||
alpha = 1.0f - alpha;
|
||||
has_alpha = true;
|
||||
}
|
||||
|
||||
@@ -31,10 +31,10 @@ AovOutput::flush(void *flush_data)
|
||||
|
||||
|
||||
void
|
||||
AccumRule::accum(const Color3 &color, std::vector<AovOutput> &outputs)const
|
||||
AccumRule::accum(const Color3& color, std::vector<AovOutput>& outputs) const
|
||||
{
|
||||
if (m_save_to_alpha) {
|
||||
outputs[m_outidx].alpha += (color.x + color.y + color.z) * 1.0f/3.0f;
|
||||
outputs[m_outidx].alpha += (color.x + color.y + color.z) * 1.0f / 3.0f;
|
||||
outputs[m_outidx].has_alpha = true;
|
||||
} else {
|
||||
outputs[m_outidx].color += color;
|
||||
@@ -44,7 +44,6 @@ AccumRule::accum(const Color3 &color, std::vector<AovOutput> &outputs)const
|
||||
|
||||
|
||||
|
||||
|
||||
AccumAutomata::~AccumAutomata()
|
||||
{
|
||||
for (auto& r : m_rules)
|
||||
@@ -53,21 +52,22 @@ AccumAutomata::~AccumAutomata()
|
||||
|
||||
|
||||
|
||||
AccumRule *
|
||||
AccumAutomata::addRule(const char *pattern, int outidx, bool toalpha)
|
||||
AccumRule*
|
||||
AccumAutomata::addRule(const char* pattern, int outidx, bool toalpha)
|
||||
{
|
||||
// First parse the lpexp and see if it fails
|
||||
Parser parser(&m_user_events, &m_user_scatterings);
|
||||
LPexp *e = parser.parse(pattern);
|
||||
LPexp* e = parser.parse(pattern);
|
||||
if (parser.error()) {
|
||||
std::cerr << "[pathexp] Parse error" << parser.getErrorMsg() << " at char " << parser.getErrorPos() << std::endl;
|
||||
std::cerr << "[pathexp] Parse error" << parser.getErrorMsg()
|
||||
<< " at char " << parser.getErrorPos() << std::endl;
|
||||
delete e;
|
||||
return NULL;
|
||||
}
|
||||
m_accumrules.emplace_back(outidx, toalpha);
|
||||
// it is a list, so as long as we don't remove it from there, the pointer is valid
|
||||
void *rule = (void *)&(m_accumrules.back());
|
||||
m_rules.push_back (new lpexp::Rule (e, rule));
|
||||
void* rule = (void*)&(m_accumrules.back());
|
||||
m_rules.push_back(new lpexp::Rule(e, rule));
|
||||
return &(m_accumrules.back());
|
||||
}
|
||||
|
||||
@@ -91,28 +91,29 @@ AccumAutomata::compile()
|
||||
|
||||
|
||||
void
|
||||
AccumAutomata::accum(int state, const Color3 &color, std::vector<AovOutput> &outputs)const
|
||||
AccumAutomata::accum(int state, const Color3& color,
|
||||
std::vector<AovOutput>& outputs) const
|
||||
{
|
||||
// get the rules field, the underlying type is a std::vector
|
||||
int nrules = 0;
|
||||
void * const * rules = getRulesInState(state, nrules);
|
||||
int nrules = 0;
|
||||
void* const* rules = getRulesInState(state, nrules);
|
||||
// Iterate the vector
|
||||
for (int i = 0; i < nrules; ++i)
|
||||
// Let the accumulator rule do its job
|
||||
((AccumRule *)(rules[i]))->accum(color, outputs);
|
||||
((AccumRule*)(rules[i]))->accum(color, outputs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Accumulator::Accumulator(const AccumAutomata *accauto)
|
||||
Accumulator::Accumulator(const AccumAutomata* accauto)
|
||||
: m_accum_automata(accauto)
|
||||
{
|
||||
const auto &rules = m_accum_automata->getRuleList();
|
||||
const auto& rules = m_accum_automata->getRuleList();
|
||||
// Make sure we have as many outputs as the rules need
|
||||
int maxouts = 0;
|
||||
for (const auto& i : rules)
|
||||
maxouts = std::max(i.getOutputIndex(), maxouts);
|
||||
m_outputs.resize(maxouts+1);
|
||||
m_outputs.resize(maxouts + 1);
|
||||
|
||||
// 0 is our initial state always
|
||||
m_state = 0;
|
||||
@@ -121,10 +122,10 @@ Accumulator::Accumulator(const AccumAutomata *accauto)
|
||||
|
||||
|
||||
void
|
||||
Accumulator::setAov(int outidx, Aov *aov, bool neg_color, bool neg_alpha)
|
||||
Accumulator::setAov(int outidx, Aov* aov, bool neg_color, bool neg_alpha)
|
||||
{
|
||||
OSL_ASSERT (0 <= outidx && outidx < (int) m_outputs.size());
|
||||
m_outputs[outidx].aov = aov;
|
||||
OSL_ASSERT(0 <= outidx && outidx < (int)m_outputs.size());
|
||||
m_outputs[outidx].aov = aov;
|
||||
m_outputs[outidx].neg_color = neg_color;
|
||||
m_outputs[outidx].neg_alpha = neg_alpha;
|
||||
}
|
||||
@@ -134,7 +135,7 @@ Accumulator::setAov(int outidx, Aov *aov, bool neg_color, bool neg_alpha)
|
||||
void
|
||||
Accumulator::pushState()
|
||||
{
|
||||
OSL_ASSERT (m_state >= 0);
|
||||
OSL_ASSERT(m_state >= 0);
|
||||
m_stack.push(m_state);
|
||||
}
|
||||
|
||||
@@ -143,7 +144,7 @@ Accumulator::pushState()
|
||||
void
|
||||
Accumulator::popState()
|
||||
{
|
||||
OSL_ASSERT (m_stack.size());
|
||||
OSL_ASSERT(m_stack.size());
|
||||
m_state = m_stack.top();
|
||||
m_stack.pop();
|
||||
}
|
||||
@@ -160,7 +161,7 @@ Accumulator::move(ustring symbol)
|
||||
|
||||
|
||||
void
|
||||
Accumulator::move(const ustring *symbols)
|
||||
Accumulator::move(const ustring* symbols)
|
||||
{
|
||||
while (m_state >= 0 && symbols && *symbols != Labels::NONE)
|
||||
m_state = m_accum_automata->getTransition(m_state, *(symbols++));
|
||||
@@ -169,7 +170,8 @@ Accumulator::move(const ustring *symbols)
|
||||
|
||||
|
||||
void
|
||||
Accumulator::move(ustring event, ustring scatt, const ustring *custom, ustring stop)
|
||||
Accumulator::move(ustring event, ustring scatt, const ustring* custom,
|
||||
ustring stop)
|
||||
{
|
||||
if (m_state >= 0)
|
||||
m_state = m_accum_automata->getTransition(m_state, event);
|
||||
@@ -193,7 +195,7 @@ Accumulator::begin()
|
||||
|
||||
|
||||
void
|
||||
Accumulator::end(void *flush_data)
|
||||
Accumulator::end(void* flush_data)
|
||||
{
|
||||
for (size_t i = 0; i < m_outputs.size(); ++i)
|
||||
m_outputs[i].flush(flush_data);
|
||||
|
||||
@@ -10,67 +10,63 @@ using namespace OSL;
|
||||
|
||||
#define END_AOV 65535
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *path[16];
|
||||
typedef struct {
|
||||
const char* path[16];
|
||||
int expected[8];
|
||||
} TestPath;
|
||||
|
||||
|
||||
// This is a fake AOV implementation. It will just keep track
|
||||
// of what test cases wrote to it
|
||||
class MyAov final : public Aov
|
||||
{
|
||||
public:
|
||||
MyAov(const TestPath *test, int id)
|
||||
{
|
||||
// Init for the test case array. For each test case set a bool
|
||||
// in m_expected marking wether this AOV should get some color
|
||||
// from that test or not.
|
||||
for (int i = 0; test[i].path[0]; ++i) { // iterate test cases
|
||||
m_expected.push_back(false); // false by default
|
||||
for (const int *expected = test[i].expected; *expected != END_AOV; ++expected)
|
||||
if (*expected == id)
|
||||
// if the AOV id is on the test's expected list, set it to true
|
||||
m_expected[i] = true;
|
||||
}
|
||||
m_received.resize(m_expected.size());
|
||||
class MyAov final : public Aov {
|
||||
public:
|
||||
MyAov(const TestPath* test, int id)
|
||||
{
|
||||
// Init for the test case array. For each test case set a bool
|
||||
// in m_expected marking whether this AOV should get some color
|
||||
// from that test or not.
|
||||
for (int i = 0; test[i].path[0]; ++i) { // iterate test cases
|
||||
m_expected.push_back(false); // false by default
|
||||
for (const int* expected = test[i].expected; *expected != END_AOV;
|
||||
++expected)
|
||||
if (*expected == id)
|
||||
// if the AOV id is on the test's expected list, set it to true
|
||||
m_expected[i] = true;
|
||||
}
|
||||
virtual ~MyAov() {}
|
||||
m_received.resize(m_expected.size());
|
||||
}
|
||||
virtual ~MyAov() {}
|
||||
|
||||
virtual void write(void *flush_data, Color3 &color, float /*alpha*/,
|
||||
bool has_color, bool /*has_alpha*/)
|
||||
{
|
||||
// our custom argument to write is the rule's number so we
|
||||
// can check what. But you normally would pass information
|
||||
// about the pixel.
|
||||
size_t testno = reinterpret_cast<size_t>(flush_data);
|
||||
if (has_color && color.x > 0)
|
||||
// only mrk with true if there is a positive color present
|
||||
m_received[testno] = true;
|
||||
else
|
||||
m_received[testno] = false;
|
||||
}
|
||||
virtual void write(void* flush_data, Color3& color, float /*alpha*/,
|
||||
bool has_color, bool /*has_alpha*/)
|
||||
{
|
||||
// our custom argument to write is the rule's number so we
|
||||
// can check what. But you normally would pass information
|
||||
// about the pixel.
|
||||
size_t testno = reinterpret_cast<size_t>(flush_data);
|
||||
if (has_color && color.x > 0)
|
||||
// only mrk with true if there is a positive color present
|
||||
m_received[testno] = true;
|
||||
else
|
||||
m_received[testno] = false;
|
||||
}
|
||||
|
||||
bool check()
|
||||
{
|
||||
return m_expected == m_received;
|
||||
}
|
||||
bool check() { return m_expected == m_received; }
|
||||
|
||||
protected:
|
||||
|
||||
std::vector<bool> m_expected;
|
||||
std::vector<bool> m_received;
|
||||
protected:
|
||||
std::vector<bool> m_expected;
|
||||
std::vector<bool> m_received;
|
||||
};
|
||||
|
||||
// Simulate the tracing of a path with the accumulator
|
||||
void simulate(Accumulator &accum, const char **events, size_t testno)
|
||||
void
|
||||
simulate(Accumulator& accum, const char** events, size_t testno)
|
||||
{
|
||||
accum.begin();
|
||||
accum.pushState();
|
||||
// for each ray stop in the path (see test cases) ...
|
||||
while (*events) {
|
||||
const char *e = *events;
|
||||
const char* e = *events;
|
||||
// for each label in this hit
|
||||
while (*e) {
|
||||
ustring sym(e, 1);
|
||||
@@ -89,9 +85,10 @@ void simulate(Accumulator &accum, const char **events, size_t testno)
|
||||
accum.end(reinterpret_cast<void*>(testno));
|
||||
}
|
||||
|
||||
int main()
|
||||
int
|
||||
main()
|
||||
{
|
||||
// Some constants to avoid refering to AOV's by number
|
||||
// Some constants to avoid referring to AOV's by number
|
||||
const int beauty = 0;
|
||||
const int diffuse2_3 = 1;
|
||||
const int light3 = 2;
|
||||
@@ -107,20 +104,29 @@ int main()
|
||||
// The actual test cases. Each one is a list of ray hits with some labels.
|
||||
// We use 1 char labels for convenience. They will be converted to ustrings
|
||||
// by simulate. And then a list of expected AOV's for each.
|
||||
TestPath test[] = { { { "C_", "TS", "TS", "RD", "L_", NULL }, { beauty, specular, nocaustic, END_AOV} },
|
||||
{ { "C_", "TS", "TS", "RD", "RG", "L_", NULL }, { END_AOV } },
|
||||
{ { "C_", "TS", "TS", "RD", "RD", "L_", NULL }, { beauty, specular, diffuse2_3, nocaustic, END_AOV } },
|
||||
{ { "C_", "RG", "RD", "RG", "RD", "RG", "RD", "L_", NULL }, { END_AOV } },
|
||||
{ { "C_", "RG", "RD", "RG", "RD", "L_", NULL }, { nocaustic, END_AOV } },
|
||||
{ { "C_", "RD", "RD", "L_", NULL }, { beauty, diffuse, diffuse2_3, nocaustic, END_AOV } },
|
||||
{ { "C_", "RD", "RS", "RD", "L_", NULL }, { nocaustic, END_AOV } },
|
||||
{ { "C_", "RD", "Ts", "L_", NULL }, { transpshadow, END_AOV } },
|
||||
{ { "C_", "TS", "TS", "RD", "L_3", NULL }, { beauty, specular, light3, nocaustic, END_AOV } },
|
||||
{ { "C_", "RD1", "RD", "L_", NULL }, { beauty, diffuse, diffuse2_3, object_1, nocaustic, END_AOV } },
|
||||
{ { "C_", "RS", "RD", "RG", "L_", NULL }, { END_AOV } },
|
||||
{ { "C_", "RS", "RD", "L_", NULL }, { beauty, specular, reflections, nocaustic, END_AOV } },
|
||||
{ { "C_", "RD", "RY", "RD", "U_", NULL }, { custom, END_AOV } },
|
||||
{ { NULL }, { END_AOV } } };
|
||||
TestPath test[]
|
||||
= { { { "C_", "TS", "TS", "RD", "L_", NULL },
|
||||
{ beauty, specular, nocaustic, END_AOV } },
|
||||
{ { "C_", "TS", "TS", "RD", "RG", "L_", NULL }, { END_AOV } },
|
||||
{ { "C_", "TS", "TS", "RD", "RD", "L_", NULL },
|
||||
{ beauty, specular, diffuse2_3, nocaustic, END_AOV } },
|
||||
{ { "C_", "RG", "RD", "RG", "RD", "RG", "RD", "L_", NULL },
|
||||
{ END_AOV } },
|
||||
{ { "C_", "RG", "RD", "RG", "RD", "L_", NULL },
|
||||
{ nocaustic, END_AOV } },
|
||||
{ { "C_", "RD", "RD", "L_", NULL },
|
||||
{ beauty, diffuse, diffuse2_3, nocaustic, END_AOV } },
|
||||
{ { "C_", "RD", "RS", "RD", "L_", NULL }, { nocaustic, END_AOV } },
|
||||
{ { "C_", "RD", "Ts", "L_", NULL }, { transpshadow, END_AOV } },
|
||||
{ { "C_", "TS", "TS", "RD", "L_3", NULL },
|
||||
{ beauty, specular, light3, nocaustic, END_AOV } },
|
||||
{ { "C_", "RD1", "RD", "L_", NULL },
|
||||
{ beauty, diffuse, diffuse2_3, object_1, nocaustic, END_AOV } },
|
||||
{ { "C_", "RS", "RD", "RG", "L_", NULL }, { END_AOV } },
|
||||
{ { "C_", "RS", "RD", "L_", NULL },
|
||||
{ beauty, specular, reflections, nocaustic, END_AOV } },
|
||||
{ { "C_", "RD", "RY", "RD", "U_", NULL }, { custom, END_AOV } },
|
||||
{ { NULL }, { END_AOV } } };
|
||||
|
||||
// Create our fake testing AOV's
|
||||
std::vector<MyAov> aovs;
|
||||
@@ -133,21 +139,21 @@ int main()
|
||||
automata.addEventType(ustring("U"));
|
||||
automata.addScatteringType(ustring("Y"));
|
||||
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C[SG]*D*L", beauty));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C[SG]*D{2,3}L", diffuse2_3));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C[SG]*D*<L.'3'>", light3));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C[SG]*D*L", beauty));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C[SG]*D{2,3}L", diffuse2_3));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C[SG]*D*<L.'3'>", light3));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C[SG]*<.D'1'>D*L", object_1));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C<.[SG]>+D*L", specular));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("CD+L", diffuse));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("CD+<Ts>L", transpshadow));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C<R[^D]>+D*L", reflections));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C([SG]*D){1,2}L", nocaustic));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("CDY+U", custom));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C<.[SG]>+D*L", specular));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("CD+L", diffuse));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("CD+<Ts>L", transpshadow));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C<R[^D]>+D*L", reflections));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("C([SG]*D){1,2}L", nocaustic));
|
||||
OIIO_CHECK_ASSERT(automata.addRule("CDY+U", custom));
|
||||
|
||||
automata.compile();
|
||||
|
||||
// now create the accumulator
|
||||
Accumulator accum (&automata);
|
||||
Accumulator accum(&automata);
|
||||
|
||||
// and set the AOV's for each id (beauty, diffuse2_3, etc ...)
|
||||
for (int i = 0; i < naovs; ++i)
|
||||
@@ -159,15 +165,15 @@ int main()
|
||||
|
||||
// And check. We unroll this loop for boost to give us a useful
|
||||
// error in case they fail
|
||||
OIIO_CHECK_ASSERT(aovs[beauty ].check());
|
||||
OIIO_CHECK_ASSERT(aovs[diffuse2_3 ].check());
|
||||
OIIO_CHECK_ASSERT(aovs[light3 ].check());
|
||||
OIIO_CHECK_ASSERT(aovs[object_1 ].check());
|
||||
OIIO_CHECK_ASSERT(aovs[specular ].check());
|
||||
OIIO_CHECK_ASSERT(aovs[diffuse ].check());
|
||||
OIIO_CHECK_ASSERT(aovs[beauty].check());
|
||||
OIIO_CHECK_ASSERT(aovs[diffuse2_3].check());
|
||||
OIIO_CHECK_ASSERT(aovs[light3].check());
|
||||
OIIO_CHECK_ASSERT(aovs[object_1].check());
|
||||
OIIO_CHECK_ASSERT(aovs[specular].check());
|
||||
OIIO_CHECK_ASSERT(aovs[diffuse].check());
|
||||
OIIO_CHECK_ASSERT(aovs[transpshadow].check());
|
||||
OIIO_CHECK_ASSERT(aovs[reflections ].check());
|
||||
OIIO_CHECK_ASSERT(aovs[nocaustic ].check());
|
||||
OIIO_CHECK_ASSERT(aovs[reflections].check());
|
||||
OIIO_CHECK_ASSERT(aovs[nocaustic].check());
|
||||
|
||||
std::cout << "Light expressions check OK" << std::endl;
|
||||
return unit_test_failures;
|
||||
|
||||
+153
-100
@@ -13,17 +13,18 @@ OSL_NAMESPACE_ENTER
|
||||
namespace Strutil = OIIO::Strutil;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf sprintf_s
|
||||
# define snprintf sprintf_s
|
||||
#endif
|
||||
|
||||
ustring lambda("__lambda__");
|
||||
|
||||
void
|
||||
NdfAutomata::State::getTransitions(ustring symbol, IntSet &out_states)const
|
||||
NdfAutomata::State::getTransitions(ustring symbol, IntSet& out_states) const
|
||||
{
|
||||
SymbolToIntList::const_iterator s = m_symbol_trans.find(symbol);
|
||||
if (s != m_symbol_trans.end())
|
||||
for (IntSet::const_iterator i = s->second.begin(); i != s->second.end(); ++i)
|
||||
for (IntSet::const_iterator i = s->second.begin(); i != s->second.end();
|
||||
++i)
|
||||
out_states.insert(*i);
|
||||
if (m_wildcard && m_wildcard->matches(symbol))
|
||||
out_states.insert(m_wildcard_trans);
|
||||
@@ -32,16 +33,15 @@ NdfAutomata::State::getTransitions(ustring symbol, IntSet &out_states)const
|
||||
|
||||
static IntSet _emptyset;
|
||||
|
||||
std::pair <IntSet::const_iterator, IntSet::const_iterator>
|
||||
NdfAutomata::State::getLambdaTransitions ()const
|
||||
std::pair<IntSet::const_iterator, IntSet::const_iterator>
|
||||
NdfAutomata::State::getLambdaTransitions() const
|
||||
{
|
||||
std::pair <IntSet::const_iterator, IntSet::const_iterator> res;
|
||||
std::pair<IntSet::const_iterator, IntSet::const_iterator> res;
|
||||
SymbolToIntList::const_iterator s = m_symbol_trans.find(lambda);
|
||||
if (s != m_symbol_trans.end()) {
|
||||
res.first = s->second.begin();
|
||||
res.first = s->second.begin();
|
||||
res.second = s->second.end();
|
||||
}
|
||||
else
|
||||
} else
|
||||
// We use a static empty list to return an empty range
|
||||
res.first = res.second = _emptyset.end();
|
||||
return res;
|
||||
@@ -50,7 +50,7 @@ NdfAutomata::State::getLambdaTransitions ()const
|
||||
|
||||
|
||||
void
|
||||
NdfAutomata::State::addTransition(ustring symbol, NdfAutomata::State *state)
|
||||
NdfAutomata::State::addTransition(ustring symbol, NdfAutomata::State* state)
|
||||
{
|
||||
m_symbol_trans[symbol].insert(state->m_id);
|
||||
}
|
||||
@@ -58,24 +58,26 @@ NdfAutomata::State::addTransition(ustring symbol, NdfAutomata::State *state)
|
||||
|
||||
|
||||
void
|
||||
NdfAutomata::State::addWildcardTransition(Wildcard *wildcard, NdfAutomata::State *state)
|
||||
NdfAutomata::State::addWildcardTransition(Wildcard* wildcard,
|
||||
NdfAutomata::State* state)
|
||||
{
|
||||
if (m_wildcard)
|
||||
std::cerr << "[pathexp] redefining wildcard transition" << std::endl;
|
||||
m_wildcard = wildcard;
|
||||
m_wildcard = wildcard;
|
||||
m_wildcard_trans = state->m_id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string
|
||||
NdfAutomata::State::tostr()const
|
||||
NdfAutomata::State::tostr() const
|
||||
{
|
||||
std::string s = "";
|
||||
// output the transitions
|
||||
for (SymbolToIntList::const_iterator i = m_symbol_trans.begin(); i != m_symbol_trans.end(); ++i) {
|
||||
ustring sym = i->first;
|
||||
const IntSet &dest = i->second;
|
||||
for (SymbolToIntList::const_iterator i = m_symbol_trans.begin();
|
||||
i != m_symbol_trans.end(); ++i) {
|
||||
ustring sym = i->first;
|
||||
const IntSet& dest = i->second;
|
||||
if (s.size())
|
||||
s += " ";
|
||||
if (sym == lambda)
|
||||
@@ -84,9 +86,9 @@ NdfAutomata::State::tostr()const
|
||||
s += sym.c_str();
|
||||
s += ":{";
|
||||
for (IntSet::const_iterator j = dest.begin(); j != dest.end(); ++j) {
|
||||
if (s[s.size()-1] != '{')
|
||||
if (s[s.size() - 1] != '{')
|
||||
s += ", ";
|
||||
s += Strutil::sprintf("%d", *j);
|
||||
s += Strutil::to_string(*j);
|
||||
}
|
||||
s += "}";
|
||||
}
|
||||
@@ -100,7 +102,8 @@ NdfAutomata::State::tostr()const
|
||||
else {
|
||||
// Standard regexp notation [^abcd]
|
||||
s += "[^";
|
||||
for (SymbolSet::const_iterator i = m_wildcard->m_minus.begin(); i != m_wildcard->m_minus.end(); ++i) {
|
||||
for (SymbolSet::const_iterator i = m_wildcard->m_minus.begin();
|
||||
i != m_wildcard->m_minus.end(); ++i) {
|
||||
if (!i->c_str())
|
||||
s += "_";
|
||||
else
|
||||
@@ -108,19 +111,19 @@ NdfAutomata::State::tostr()const
|
||||
}
|
||||
s += "]:";
|
||||
}
|
||||
s += Strutil::sprintf("%d", m_wildcard_trans);
|
||||
s += Strutil::to_string(m_wildcard_trans);
|
||||
}
|
||||
// and finally the rule if we have it
|
||||
if (m_rule) {
|
||||
s += " | ";
|
||||
s += Strutil::sprintf("%p", m_rule);
|
||||
s += Strutil::fmt::format("{:p}", m_rule);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NdfAutomata::State *
|
||||
NdfAutomata::State*
|
||||
NdfAutomata::newState()
|
||||
{
|
||||
m_states.push_back(new State(m_states.size()));
|
||||
@@ -130,13 +133,15 @@ NdfAutomata::newState()
|
||||
|
||||
|
||||
void
|
||||
NdfAutomata::symbolsFrom(const IntSet &states, SymbolSet &out_symbols, Wildcard *&wildcard)const
|
||||
NdfAutomata::symbolsFrom(const IntSet& states, SymbolSet& out_symbols,
|
||||
Wildcard*& wildcard) const
|
||||
{
|
||||
for (IntSet::const_iterator i = states.begin(); i != states.end(); ++i) {
|
||||
const State *state = m_states[*i];
|
||||
// For every state we have to go thorugh all the symbols in the transition table
|
||||
const State* state = m_states[*i];
|
||||
// For every state we have to go through all the symbols in the transition table
|
||||
// m_symbol_trans and add them to the output
|
||||
for (SymbolToIntList::const_iterator j = state->m_symbol_trans.begin(); j != state->m_symbol_trans.end(); ++j)
|
||||
for (SymbolToIntList::const_iterator j = state->m_symbol_trans.begin();
|
||||
j != state->m_symbol_trans.end(); ++j)
|
||||
if (j->first != lambda)
|
||||
out_symbols.insert(j->first);
|
||||
if (state->m_wildcard) {
|
||||
@@ -145,16 +150,19 @@ NdfAutomata::symbolsFrom(const IntSet &states, SymbolSet &out_symbols, Wildcard
|
||||
// And if the state has a wildcard movement, we need to add its exclusion list
|
||||
// to our new computed exclusion list. So we guarantee that the returned wildcard
|
||||
// matches will be contained in all the wildcards out of this set
|
||||
wildcard->m_minus.insert(state->m_wildcard->m_minus.begin(), state->m_wildcard->m_minus.end());
|
||||
wildcard->m_minus.insert(state->m_wildcard->m_minus.begin(),
|
||||
state->m_wildcard->m_minus.end());
|
||||
}
|
||||
}
|
||||
if (wildcard) {
|
||||
// We have to make sure that all the symbols covered by the wildcards
|
||||
// are either covered by our wildcard or in out_symbols set
|
||||
for (IntSet::const_iterator i = states.begin(); i != states.end(); ++i) {
|
||||
const State *state = m_states[*i];
|
||||
for (IntSet::const_iterator i = states.begin(); i != states.end();
|
||||
++i) {
|
||||
const State* state = m_states[*i];
|
||||
if (state->m_wildcard)
|
||||
for (SymbolSet::const_iterator j = wildcard->m_minus.begin(); j != wildcard->m_minus.end(); ++j)
|
||||
for (SymbolSet::const_iterator j = wildcard->m_minus.begin();
|
||||
j != wildcard->m_minus.end(); ++j)
|
||||
if (state->m_wildcard->matches(*j))
|
||||
out_symbols.insert(*j);
|
||||
}
|
||||
@@ -166,7 +174,8 @@ NdfAutomata::symbolsFrom(const IntSet &states, SymbolSet &out_symbols, Wildcard
|
||||
|
||||
|
||||
void
|
||||
NdfAutomata::transitionsFrom(const IntSet &states, ustring symbol, IntSet &out_states)const
|
||||
NdfAutomata::transitionsFrom(const IntSet& states, ustring symbol,
|
||||
IntSet& out_states) const
|
||||
{
|
||||
for (IntSet::const_iterator i = states.begin(); i != states.end(); ++i)
|
||||
// remember getTransitions is not destructive with out_states, it just adds stuff
|
||||
@@ -178,10 +187,11 @@ NdfAutomata::transitionsFrom(const IntSet &states, ustring symbol, IntSet &out_s
|
||||
|
||||
|
||||
void
|
||||
NdfAutomata::wildcardTransitionsFrom(const IntSet &states, IntSet &out_states)const
|
||||
NdfAutomata::wildcardTransitionsFrom(const IntSet& states,
|
||||
IntSet& out_states) const
|
||||
{
|
||||
for (IntSet::const_iterator i = states.begin(); i != states.end(); ++i) {
|
||||
const State *state = m_states[*i];
|
||||
const State* state = m_states[*i];
|
||||
if (state->m_wildcard)
|
||||
out_states.insert(state->m_wildcard_trans);
|
||||
}
|
||||
@@ -191,7 +201,7 @@ NdfAutomata::wildcardTransitionsFrom(const IntSet &states, IntSet &out_states)co
|
||||
|
||||
|
||||
void
|
||||
NdfAutomata::lambdaClosure(IntSet &states)const
|
||||
NdfAutomata::lambdaClosure(IntSet& states) const
|
||||
{
|
||||
// This algorithm basically keeps expanding the set until no new states appear
|
||||
// to avoid checking over and over the same states we keep a frontier pair of sets
|
||||
@@ -200,40 +210,42 @@ NdfAutomata::lambdaClosure(IntSet &states)const
|
||||
// First iterate all the states in the given set
|
||||
// and see what lambda transitions are there
|
||||
for (IntSet::const_iterator i = states.begin(); i != states.end(); ++i) {
|
||||
const State *state = m_states[*i];
|
||||
std::pair <IntSet::const_iterator, IntSet::const_iterator> lr;
|
||||
const State* state = m_states[*i];
|
||||
std::pair<IntSet::const_iterator, IntSet::const_iterator> lr;
|
||||
// iterate all lambda transitions for this state
|
||||
for (lr = state->getLambdaTransitions(); lr.first != lr.second; lr.first++) {
|
||||
for (lr = state->getLambdaTransitions(); lr.first != lr.second;
|
||||
lr.first++) {
|
||||
// Add them to the set, and if they were not already there add to the
|
||||
// frontier
|
||||
std::pair<IntSet::iterator, bool> rec = states.insert(*(lr.first));
|
||||
if (rec.second) // newly added
|
||||
if (rec.second) // newly added
|
||||
frontier.push_back(*(lr.first));
|
||||
}
|
||||
}
|
||||
// frontier becomes last discovered
|
||||
frontier.swap(discovered); // swap discovered and frontier
|
||||
while (discovered.size()) { // as long as there are new found states
|
||||
frontier.swap(discovered); // swap discovered and frontier
|
||||
while (discovered.size()) { // as long as there are new found states
|
||||
frontier.clear();
|
||||
// we do the same as in the above loop but with discovered instead of states
|
||||
for (auto i : discovered) {
|
||||
const State *state = m_states[i];
|
||||
for (auto lr = state->getLambdaTransitions(); lr.first != lr.second; lr.first++) {
|
||||
std::pair<IntSet::iterator, bool> rec = states.insert(*(lr.first));
|
||||
const State* state = m_states[i];
|
||||
for (auto lr = state->getLambdaTransitions(); lr.first != lr.second;
|
||||
lr.first++) {
|
||||
std::pair<IntSet::iterator, bool> rec = states.insert(
|
||||
*(lr.first));
|
||||
if (rec.second)
|
||||
frontier.push_back(*(lr.first));
|
||||
}
|
||||
|
||||
}
|
||||
// again frontier becomes last discovered
|
||||
frontier.swap(discovered); // swap discovered and frontier
|
||||
frontier.swap(discovered); // swap discovered and frontier
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string
|
||||
NdfAutomata::tostr()const
|
||||
NdfAutomata::tostr() const
|
||||
{
|
||||
std::string s;
|
||||
for (size_t i = 0; i < m_states.size(); ++i) {
|
||||
@@ -254,9 +266,10 @@ NdfAutomata::~NdfAutomata()
|
||||
|
||||
|
||||
|
||||
void keyFromStateSet(const IntSet &states, StateSetKey &out_key)
|
||||
void
|
||||
keyFromStateSet(const IntSet& states, StateSetKey& out_key)
|
||||
{
|
||||
out_key.clear(); // just in case
|
||||
out_key.clear(); // just in case
|
||||
for (IntSet::const_iterator i = states.begin(); i != states.end(); ++i)
|
||||
out_key.push_back(*i);
|
||||
// Sort the ids so we make sure the vector is unique for each set
|
||||
@@ -266,7 +279,7 @@ void keyFromStateSet(const IntSet &states, StateSetKey &out_key)
|
||||
|
||||
|
||||
int
|
||||
DfAutomata::State::getTransition(ustring symbol)const
|
||||
DfAutomata::State::getTransition(ustring symbol) const
|
||||
{
|
||||
SymbolToInt::const_iterator i = m_symbol_trans.find(symbol);
|
||||
if (i == m_symbol_trans.end())
|
||||
@@ -281,20 +294,23 @@ DfAutomata::State::getTransition(ustring symbol)const
|
||||
|
||||
|
||||
void
|
||||
DfAutomata::State::addTransition(ustring symbol, DfAutomata::State *state)
|
||||
DfAutomata::State::addTransition(ustring symbol, DfAutomata::State* state)
|
||||
{
|
||||
SymbolToInt::value_type value(symbol, state->m_id);
|
||||
std::pair<SymbolToInt::iterator, bool> place = m_symbol_trans.insert(value);
|
||||
if (!place.second)
|
||||
std::cerr << "[pathexp] overwriting a transition in a DF automata" << std::endl;
|
||||
std::cerr << "[pathexp] overwriting a transition in a DF automata"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
DfAutomata::State::addWildcardTransition(Wildcard *wildcard, DfAutomata::State *state)
|
||||
DfAutomata::State::addWildcardTransition(Wildcard* wildcard,
|
||||
DfAutomata::State* state)
|
||||
{
|
||||
for (SymbolSet::const_iterator i = wildcard->m_minus.begin(); i != wildcard->m_minus.end(); ++i)
|
||||
for (SymbolSet::const_iterator i = wildcard->m_minus.begin();
|
||||
i != wildcard->m_minus.end(); ++i)
|
||||
// optimized storage, if it is not already in the transition table, tag it with -1
|
||||
if (m_symbol_trans.find(*i) == m_symbol_trans.end())
|
||||
m_symbol_trans[*i] = -1;
|
||||
@@ -309,7 +325,8 @@ DfAutomata::State::removeUselessTransitions()
|
||||
{
|
||||
if (m_wildcard_trans >= 0) {
|
||||
std::list<SymbolToInt::iterator> toremove;
|
||||
for (SymbolToInt::iterator i = m_symbol_trans.begin(); i != m_symbol_trans.end(); ++i)
|
||||
for (SymbolToInt::iterator i = m_symbol_trans.begin();
|
||||
i != m_symbol_trans.end(); ++i)
|
||||
// If there is a transition to the same state as the wildcard, we better nuke it
|
||||
// and just add that symbol to the wildcard be removing it from the map itself
|
||||
if (i->second == m_wildcard_trans)
|
||||
@@ -322,13 +339,14 @@ DfAutomata::State::removeUselessTransitions()
|
||||
|
||||
|
||||
std::string
|
||||
DfAutomata::State::tostr()const
|
||||
DfAutomata::State::tostr() const
|
||||
{
|
||||
std::string s = "";
|
||||
// normal transitions
|
||||
for (SymbolToInt::const_iterator i = m_symbol_trans.begin(); i != m_symbol_trans.end(); ++i) {
|
||||
for (SymbolToInt::const_iterator i = m_symbol_trans.begin();
|
||||
i != m_symbol_trans.end(); ++i) {
|
||||
ustring sym = i->first;
|
||||
int dest = i->second;
|
||||
int dest = i->second;
|
||||
if (s.size())
|
||||
s += " ";
|
||||
if (sym == lambda)
|
||||
@@ -336,7 +354,7 @@ DfAutomata::State::tostr()const
|
||||
else
|
||||
s += sym.c_str();
|
||||
s += ":";
|
||||
s += Strutil::sprintf("%d", dest);
|
||||
s += Strutil::to_string(dest);
|
||||
}
|
||||
// wildcard
|
||||
if (m_wildcard_trans >= 0) {
|
||||
@@ -346,7 +364,8 @@ DfAutomata::State::tostr()const
|
||||
s += ".:";
|
||||
else {
|
||||
s += "[^";
|
||||
for (SymbolToInt::const_iterator i = m_symbol_trans.begin(); i != m_symbol_trans.end(); ++i) {
|
||||
for (SymbolToInt::const_iterator i = m_symbol_trans.begin();
|
||||
i != m_symbol_trans.end(); ++i) {
|
||||
if (!i->first.c_str())
|
||||
s += "_";
|
||||
else
|
||||
@@ -354,15 +373,16 @@ DfAutomata::State::tostr()const
|
||||
}
|
||||
s += "}:";
|
||||
}
|
||||
s += Strutil::sprintf("%d", m_wildcard_trans);
|
||||
s += Strutil::to_string(m_wildcard_trans);
|
||||
}
|
||||
// and the rules
|
||||
if (m_rules.size()) {
|
||||
s += " | [";
|
||||
for (RuleSet::const_iterator i = m_rules.begin(); i != m_rules.end(); ++i) {
|
||||
if (s[s.size()-1] != '[')
|
||||
for (RuleSet::const_iterator i = m_rules.begin(); i != m_rules.end();
|
||||
++i) {
|
||||
if (s[s.size() - 1] != '[')
|
||||
s += ", ";
|
||||
s += Strutil::sprintf("%p", *i);
|
||||
s += Strutil::fmt::format("{:p}", *i);
|
||||
}
|
||||
s += "]";
|
||||
}
|
||||
@@ -371,7 +391,7 @@ DfAutomata::State::tostr()const
|
||||
|
||||
|
||||
|
||||
DfAutomata::State *
|
||||
DfAutomata::State*
|
||||
DfAutomata::newState()
|
||||
{
|
||||
m_states.push_back(new State(m_states.size()));
|
||||
@@ -381,7 +401,7 @@ DfAutomata::newState()
|
||||
|
||||
|
||||
std::string
|
||||
DfAutomata::tostr()const
|
||||
DfAutomata::tostr() const
|
||||
{
|
||||
std::string s;
|
||||
for (size_t i = 0; i < m_states.size(); ++i) {
|
||||
@@ -395,26 +415,40 @@ DfAutomata::tostr()const
|
||||
|
||||
|
||||
bool
|
||||
DfAutomata::equivalent(const State *dfstateA, const State *dfstateB)
|
||||
DfAutomata::equivalent(const State* dfstateA, const State* dfstateB)
|
||||
{
|
||||
// early exit if the size of the tables is different
|
||||
if (dfstateA->m_symbol_trans.size() != dfstateB->m_symbol_trans.size())
|
||||
return false;
|
||||
// The pointed state by both transitions have to be the same or any of dfstateA and dfstateB
|
||||
int destA = (dfstateA->m_wildcard_trans == dfstateA->getId() || dfstateA->m_wildcard_trans == dfstateB->getId()) ? -2 : dfstateA->m_wildcard_trans;
|
||||
int destB = (dfstateB->m_wildcard_trans == dfstateA->getId() || dfstateB->m_wildcard_trans == dfstateB->getId()) ? -2 : dfstateB->m_wildcard_trans;
|
||||
int destA = (dfstateA->m_wildcard_trans == dfstateA->getId()
|
||||
|| dfstateA->m_wildcard_trans == dfstateB->getId())
|
||||
? -2
|
||||
: dfstateA->m_wildcard_trans;
|
||||
int destB = (dfstateB->m_wildcard_trans == dfstateA->getId()
|
||||
|| dfstateB->m_wildcard_trans == dfstateB->getId())
|
||||
? -2
|
||||
: dfstateB->m_wildcard_trans;
|
||||
if (destA != destB)
|
||||
return false;
|
||||
// Rules have to be the same
|
||||
if (dfstateA->m_rules != dfstateB->m_rules)
|
||||
return false;
|
||||
for (SymbolToInt::const_iterator i = dfstateA->m_symbol_trans.begin(); i != dfstateA->m_symbol_trans.end(); ++i) {
|
||||
SymbolToInt::const_iterator other = dfstateB->m_symbol_trans.find(i->first);
|
||||
for (SymbolToInt::const_iterator i = dfstateA->m_symbol_trans.begin();
|
||||
i != dfstateA->m_symbol_trans.end(); ++i) {
|
||||
SymbolToInt::const_iterator other = dfstateB->m_symbol_trans.find(
|
||||
i->first);
|
||||
if (other == dfstateB->m_symbol_trans.end())
|
||||
return false;
|
||||
// The pointed state by both transitions have to be the same or any of dfstateA and dfstateB
|
||||
int destA = (i->second == dfstateA->getId() || i->second == dfstateB->getId()) ? -2 : i->second;
|
||||
int destB = (other->second == dfstateA->getId() || other->second == dfstateB->getId()) ? -2 : other->second;
|
||||
int destA = (i->second == dfstateA->getId()
|
||||
|| i->second == dfstateB->getId())
|
||||
? -2
|
||||
: i->second;
|
||||
int destB = (other->second == dfstateA->getId()
|
||||
|| other->second == dfstateB->getId())
|
||||
? -2
|
||||
: other->second;
|
||||
// when they are -1 is because they are in the wildcard black list, anyway they have to match so ...
|
||||
if (destA != destB)
|
||||
return false;
|
||||
@@ -428,13 +462,13 @@ DfAutomata::equivalent(const State *dfstateA, const State *dfstateB)
|
||||
void
|
||||
DfAutomata::removeEquivalentStates()
|
||||
{
|
||||
std::vector<State *> newstatelist;
|
||||
std::vector<State*> newstatelist;
|
||||
HashIntInt newfromold;
|
||||
|
||||
// First go through all states and delete all those
|
||||
// that are equivalent with a previous one
|
||||
for (size_t i = 0; i < m_states.size(); ++i) {
|
||||
if (!m_states[i]) // it has already been removed
|
||||
if (!m_states[i]) // it has already been removed
|
||||
continue;
|
||||
// create a new state id from newstatelist.size()
|
||||
// move the pointer there and register the translation
|
||||
@@ -452,24 +486,30 @@ DfAutomata::removeEquivalentStates()
|
||||
// Everything has been moved now, but we still have to fix the
|
||||
// transitions so they point to the right states!
|
||||
for (size_t i = 0; i < newstatelist.size(); ++i) {
|
||||
State *state = newstatelist[i];
|
||||
for (SymbolToInt::iterator j = state->m_symbol_trans.begin(); j != state->m_symbol_trans.end(); ++j) {
|
||||
if (j->second != -1) { // if it is -1 it is just in the wildcards black list
|
||||
State* state = newstatelist[i];
|
||||
for (SymbolToInt::iterator j = state->m_symbol_trans.begin();
|
||||
j != state->m_symbol_trans.end(); ++j) {
|
||||
if (j->second
|
||||
!= -1) { // if it is -1 it is just in the wildcards black list
|
||||
// Get the new state that maps to the oldstate pointed by the transition
|
||||
HashIntInt::const_iterator trans = newfromold.find(j->second);
|
||||
if (trans != newfromold.end())
|
||||
j->second = trans->second;
|
||||
else
|
||||
std::cerr << "[pathexp] broken translation list between states" << std::endl;
|
||||
std::cerr
|
||||
<< "[pathexp] broken translation list between states"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
// Do the same with the wildcard
|
||||
if (state->m_wildcard_trans >=0) {
|
||||
HashIntInt::const_iterator trans = newfromold.find(state->m_wildcard_trans);
|
||||
if (state->m_wildcard_trans >= 0) {
|
||||
HashIntInt::const_iterator trans = newfromold.find(
|
||||
state->m_wildcard_trans);
|
||||
if (trans != newfromold.end())
|
||||
state->m_wildcard_trans = trans->second;
|
||||
else
|
||||
std::cerr << "[pathexp] broken translation list between states" << std::endl;
|
||||
std::cerr << "[pathexp] broken translation list between states"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
// switch to the new hopefully reduced state vector
|
||||
@@ -504,8 +544,9 @@ DfAutomata::~DfAutomata()
|
||||
|
||||
|
||||
|
||||
DfAutomata::State *
|
||||
StateSetRecord::ensureState(const IntSet &newstates, std::list<StateSetRecord::Discovery> &discovered)
|
||||
DfAutomata::State*
|
||||
StateSetRecord::ensureState(const IntSet& newstates,
|
||||
std::list<StateSetRecord::Discovery>& discovered)
|
||||
{
|
||||
// create the key
|
||||
StateSetKey newkey;
|
||||
@@ -516,7 +557,7 @@ StateSetRecord::ensureState(const IntSet &newstates, std::list<StateSetRecord::D
|
||||
return i->second;
|
||||
else {
|
||||
// if not in our records create a new DF state
|
||||
DfAutomata::State *tstate = m_dfautomata.newState();
|
||||
DfAutomata::State* tstate = m_dfautomata.newState();
|
||||
getRulesFromSet(tstate, m_ndfautomata, newstates);
|
||||
m_key_to_dfstate[newkey] = tstate;
|
||||
// Add the discovery to the list so it will be explored
|
||||
@@ -528,10 +569,13 @@ StateSetRecord::ensureState(const IntSet &newstates, std::list<StateSetRecord::D
|
||||
|
||||
|
||||
void
|
||||
StateSetRecord::getRulesFromSet(DfAutomata::State *dfstate, const NdfAutomata &ndfautomata, const IntSet &ndfstates)
|
||||
StateSetRecord::getRulesFromSet(DfAutomata::State* dfstate,
|
||||
const NdfAutomata& ndfautomata,
|
||||
const IntSet& ndfstates)
|
||||
{
|
||||
for (IntSet::const_iterator i = ndfstates.begin(); i != ndfstates.end(); ++i) {
|
||||
const NdfAutomata::State *ndfstate = ndfautomata.getState(*i);
|
||||
for (IntSet::const_iterator i = ndfstates.begin(); i != ndfstates.end();
|
||||
++i) {
|
||||
const NdfAutomata::State* ndfstate = ndfautomata.getState(*i);
|
||||
if (ndfstate->getRule())
|
||||
dfstate->addRule(ndfstate->getRule());
|
||||
}
|
||||
@@ -540,7 +584,7 @@ StateSetRecord::getRulesFromSet(DfAutomata::State *dfstate, const NdfAutomata &n
|
||||
|
||||
|
||||
void
|
||||
ndfautoToDfauto(const NdfAutomata &ndfautomata, DfAutomata &dfautomata)
|
||||
ndfautoToDfauto(const NdfAutomata& ndfautomata, DfAutomata& dfautomata)
|
||||
{
|
||||
std::list<StateSetRecord::Discovery> toexplore, discovered;
|
||||
// our initial state is the lambda closure
|
||||
@@ -561,14 +605,16 @@ ndfautoToDfauto(const NdfAutomata &ndfautomata, DfAutomata &dfautomata)
|
||||
// a wildcard movement that is guaranteed to match all
|
||||
// the wildcard transitions in the set (if any)
|
||||
SymbolSet symbols;
|
||||
Wildcard *wildcard = NULL;
|
||||
Wildcard* wildcard = NULL;
|
||||
ndfautomata.symbolsFrom(i.second, symbols, wildcard);
|
||||
for (SymbolSet::iterator j = symbols.begin(); j != symbols.end(); ++j) {
|
||||
for (SymbolSet::iterator j = symbols.begin(); j != symbols.end();
|
||||
++j) {
|
||||
IntSet newstates;
|
||||
// get all the states reachable with this symbol
|
||||
ndfautomata.transitionsFrom(i.second, *j, newstates);
|
||||
// build or recover the associated DF state
|
||||
DfAutomata::State *next_state = record.ensureState(newstates, discovered);
|
||||
DfAutomata::State* next_state = record.ensureState(newstates,
|
||||
discovered);
|
||||
// and store a transition
|
||||
i.first->addTransition(*j, next_state);
|
||||
}
|
||||
@@ -577,7 +623,8 @@ ndfautoToDfauto(const NdfAutomata &ndfautomata, DfAutomata &dfautomata)
|
||||
// we know they all match whatever ours match
|
||||
ndfautomata.wildcardTransitionsFrom(i.second, newstates);
|
||||
// build or recover the associated DF state
|
||||
DfAutomata::State *next_state = record.ensureState(newstates, discovered);
|
||||
DfAutomata::State* next_state = record.ensureState(newstates,
|
||||
discovered);
|
||||
// and store a transition
|
||||
i.first->addWildcardTransition(wildcard, next_state);
|
||||
}
|
||||
@@ -593,7 +640,9 @@ ndfautoToDfauto(const NdfAutomata &ndfautomata, DfAutomata &dfautomata)
|
||||
|
||||
|
||||
bool
|
||||
DfOptimizedAutomata::Transition::trans_comp (const DfOptimizedAutomata::Transition &a, const DfOptimizedAutomata::Transition &b)
|
||||
DfOptimizedAutomata::Transition::trans_comp(
|
||||
const DfOptimizedAutomata::Transition& a,
|
||||
const DfOptimizedAutomata::Transition& b)
|
||||
{
|
||||
return a.symbol.data() < b.symbol.data();
|
||||
}
|
||||
@@ -601,7 +650,7 @@ DfOptimizedAutomata::Transition::trans_comp (const DfOptimizedAutomata::Transiti
|
||||
|
||||
|
||||
void
|
||||
DfOptimizedAutomata::compileFrom(const DfAutomata &dfautomata)
|
||||
DfOptimizedAutomata::compileFrom(const DfAutomata& dfautomata)
|
||||
{
|
||||
m_states.resize(dfautomata.m_states.size());
|
||||
size_t totaltrans = 0;
|
||||
@@ -617,18 +666,22 @@ DfOptimizedAutomata::compileFrom(const DfAutomata &dfautomata)
|
||||
for (size_t s = 0; s < m_states.size(); ++s) {
|
||||
m_states[s].begin_trans = trans_offset;
|
||||
m_states[s].begin_rules = rules_offset;
|
||||
for (SymbolToInt::const_iterator i = dfautomata.m_states[s]->m_symbol_trans.begin();
|
||||
i != dfautomata.m_states[s]->m_symbol_trans.end(); ++i, ++trans_offset) {
|
||||
for (SymbolToInt::const_iterator i
|
||||
= dfautomata.m_states[s]->m_symbol_trans.begin();
|
||||
i != dfautomata.m_states[s]->m_symbol_trans.end();
|
||||
++i, ++trans_offset) {
|
||||
m_trans[trans_offset].symbol = i->first;
|
||||
m_trans[trans_offset].state = i->second;
|
||||
m_trans[trans_offset].state = i->second;
|
||||
}
|
||||
for (RuleSet::const_iterator i = dfautomata.m_states[s]->m_rules.begin();
|
||||
i != dfautomata.m_states[s]->m_rules.end(); ++i, ++rules_offset)
|
||||
i != dfautomata.m_states[s]->m_rules.end(); ++i, ++rules_offset)
|
||||
m_rules[rules_offset] = *i;
|
||||
m_states[s].ntrans = dfautomata.m_states[s]->m_symbol_trans.size();
|
||||
m_states[s].nrules = dfautomata.m_states[s]->m_rules.size();
|
||||
std::sort(m_trans.begin() + m_states[s].begin_trans, m_trans.begin() + m_states[s].begin_trans + m_states[s].ntrans,
|
||||
DfOptimizedAutomata::Transition::trans_comp);
|
||||
std::sort(m_trans.begin() + m_states[s].begin_trans,
|
||||
m_trans.begin() + m_states[s].begin_trans
|
||||
+ m_states[s].ntrans,
|
||||
DfOptimizedAutomata::Transition::trans_comp);
|
||||
m_states[s].wildcard_trans = dfautomata.m_states[s]->m_wildcard_trans;
|
||||
}
|
||||
}
|
||||
|
||||
+202
-198
@@ -4,12 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <OSL/oslconfig.h>
|
||||
|
||||
@@ -20,20 +20,21 @@ OSL_NAMESPACE_ENTER
|
||||
// General container for all symbol sets
|
||||
|
||||
// General container for integer sets
|
||||
typedef std::set<int> IntSet; // probably faster to test for equality, unions and so
|
||||
typedef std::set<int>
|
||||
IntSet; // probably faster to test for equality, unions and so
|
||||
|
||||
typedef std::unordered_set<ustring, ustringHash> SymbolSet;
|
||||
typedef std::unordered_set<ustring> SymbolSet;
|
||||
// This is for the transition table used in DfAutomata::State
|
||||
typedef std::unordered_map<ustring, int, ustringHash> SymbolToInt;
|
||||
typedef std::unordered_map<ustring, int> SymbolToInt;
|
||||
// And this is for the transition table in NdfAutomata which
|
||||
// has several movements for each symbol
|
||||
typedef std::unordered_map<ustring, IntSet, ustringHash> SymbolToIntList;
|
||||
typedef std::unordered_map<ustring, IntSet> SymbolToIntList;
|
||||
typedef std::unordered_map<int, int> HashIntInt;
|
||||
|
||||
// For the rules in the deterministic states, we don't need a real set
|
||||
// cause when converting from the NDF automata we will never find the same
|
||||
// rule twice
|
||||
typedef std::vector<void *> RuleSet;
|
||||
typedef std::vector<void*> RuleSet;
|
||||
|
||||
// The lambda symbol (empty word)
|
||||
extern ustring lambda;
|
||||
@@ -45,9 +46,9 @@ extern ustring lambda;
|
||||
/// any symbol which is not listed in its black list (m_minus).
|
||||
struct Wildcard {
|
||||
Wildcard() {};
|
||||
Wildcard(SymbolSet &minus):m_minus(minus) {};
|
||||
Wildcard(SymbolSet& minus) : m_minus(minus) {};
|
||||
|
||||
bool matches(ustring symbol)const
|
||||
bool matches(ustring symbol) const
|
||||
{
|
||||
// true if the given symbol is not in m_minus
|
||||
return (m_minus.find(symbol) == m_minus.end());
|
||||
@@ -63,109 +64,110 @@ struct Wildcard {
|
||||
/// symbol and allowed lambda transitions too. Light path expressions
|
||||
/// build this automata easily. It is later converted to a DF automata.
|
||||
class NdfAutomata {
|
||||
public:
|
||||
// Basic state for NDF automata
|
||||
class State {
|
||||
friend class NdfAutomata;
|
||||
|
||||
public:
|
||||
|
||||
// Basic state for NDF automata
|
||||
class State {
|
||||
friend class NdfAutomata;
|
||||
public:
|
||||
|
||||
State(int id)
|
||||
{
|
||||
m_id = id;
|
||||
m_wildcard_trans = -1;
|
||||
m_wildcard = NULL;
|
||||
m_rule = NULL;
|
||||
};
|
||||
~State() { delete m_wildcard; };
|
||||
|
||||
/// Get the set of state id's reachable by the given symbol
|
||||
///
|
||||
/// It doesn't clean the given result set, so you can use this
|
||||
/// function to accumulate states.
|
||||
void getTransitions (ustring symbol, IntSet &out_states)const;
|
||||
|
||||
/// Get all the lambda transitions
|
||||
///
|
||||
/// Returns the state collection as a pair of iterators [begin, end)
|
||||
std::pair <IntSet::const_iterator, IntSet::const_iterator>
|
||||
getLambdaTransitions ()const;
|
||||
|
||||
/// Add a standar transition (also valid for lambda)
|
||||
void addTransition (ustring symbol, State *state);
|
||||
/// Add a wildcard transition
|
||||
///
|
||||
/// Note that the state is going to take ownership of the wildcard
|
||||
/// pointer. So it should be newly allocated on heap and you don't
|
||||
/// have to delete ir
|
||||
void addWildcardTransition(Wildcard *wildcard, State *state);
|
||||
|
||||
/// For final states, this sets the associated rule. Which
|
||||
/// can be any kind of pointer
|
||||
void setRule(void *rule) { m_rule = rule; };
|
||||
|
||||
void *getRule()const { return m_rule; };
|
||||
int getId()const { return m_id; };
|
||||
|
||||
/// For debuging purposes
|
||||
std::string tostr()const;
|
||||
|
||||
protected:
|
||||
|
||||
// State id (i.e index in the states vector)
|
||||
int m_id;
|
||||
// Transitions by single symbols
|
||||
SymbolToIntList m_symbol_trans;
|
||||
// In case m_wildcard is not NULL this holds the destination
|
||||
// of the wildcard transition
|
||||
int m_wildcard_trans;
|
||||
// Wildcard (NULL if no wildcard transition present)
|
||||
Wildcard *m_wildcard;
|
||||
// Associated rule for final states, NULL if not final
|
||||
void *m_rule;
|
||||
State(int id)
|
||||
{
|
||||
m_id = id;
|
||||
m_wildcard_trans = -1;
|
||||
m_wildcard = NULL;
|
||||
m_rule = NULL;
|
||||
};
|
||||
~State() { delete m_wildcard; };
|
||||
|
||||
|
||||
|
||||
NdfAutomata() { newState(); };
|
||||
~NdfAutomata();
|
||||
|
||||
const State *getInitial()const { return m_states[0]; };
|
||||
State *getInitial() { return m_states[0]; };
|
||||
|
||||
/// Creates a new state qith a valid id
|
||||
State *newState();
|
||||
|
||||
const State *getState(int i)const { return m_states[i]; };
|
||||
size_t size()const { return m_states.size(); };
|
||||
|
||||
/// return all the symbols that lead to other states starting
|
||||
/// in any of the states in the given set. Also if there are
|
||||
/// wildcard transitions, give back a new wildcard that guarantees
|
||||
/// that its matches match all the wildcards in the set.
|
||||
/// So the symbols returned in out_symbols do NOT overlap those that
|
||||
/// match the returned wildcard (if present). And the union of out_symbols
|
||||
/// and those matched by the wildcard, are all the valid transitions from
|
||||
/// the given state set
|
||||
void symbolsFrom(const IntSet &states, SymbolSet &out_symbols, Wildcard *&wildcard)const;
|
||||
|
||||
/// Get the set of states that are reachable from the given state set using the given symbol
|
||||
void transitionsFrom(const IntSet &states, ustring symbol, IntSet &out_states)const;
|
||||
/// Get the set of states that are reachable from the given state set by wildcard
|
||||
void wildcardTransitionsFrom(const IntSet &states, IntSet &out_states)const;
|
||||
|
||||
/// Perform a lambda closure of a state set
|
||||
/// Get the set of state id's reachable by the given symbol
|
||||
///
|
||||
/// In other words, complete the given set so it includes all the additional
|
||||
/// states that are reachable by the lambda symbol
|
||||
void lambdaClosure(IntSet &states)const;
|
||||
/// It doesn't clean the given result set, so you can use this
|
||||
/// function to accumulate states.
|
||||
void getTransitions(ustring symbol, IntSet& out_states) const;
|
||||
|
||||
/// for debuging purposes
|
||||
std::string tostr()const;
|
||||
/// Get all the lambda transitions
|
||||
///
|
||||
/// Returns the state collection as a pair of iterators [begin, end)
|
||||
std::pair<IntSet::const_iterator, IntSet::const_iterator>
|
||||
getLambdaTransitions() const;
|
||||
|
||||
/// Add a standard transition (also valid for lambda)
|
||||
void addTransition(ustring symbol, State* state);
|
||||
/// Add a wildcard transition
|
||||
///
|
||||
/// Note that the state is going to take ownership of the wildcard
|
||||
/// pointer. So it should be newly allocated on heap and you don't
|
||||
/// have to delete ir
|
||||
void addWildcardTransition(Wildcard* wildcard, State* state);
|
||||
|
||||
/// For final states, this sets the associated rule. Which
|
||||
/// can be any kind of pointer
|
||||
void setRule(void* rule) { m_rule = rule; };
|
||||
|
||||
void* getRule() const { return m_rule; };
|
||||
int getId() const { return m_id; };
|
||||
|
||||
/// For debugging purposes
|
||||
std::string tostr() const;
|
||||
|
||||
protected:
|
||||
/// Vector of states
|
||||
std::vector<State *> m_states;
|
||||
// State id (i.e index in the states vector)
|
||||
int m_id;
|
||||
// Transitions by single symbols
|
||||
SymbolToIntList m_symbol_trans;
|
||||
// In case m_wildcard is not NULL this holds the destination
|
||||
// of the wildcard transition
|
||||
int m_wildcard_trans;
|
||||
// Wildcard (NULL if no wildcard transition present)
|
||||
Wildcard* m_wildcard;
|
||||
// Associated rule for final states, NULL if not final
|
||||
void* m_rule;
|
||||
};
|
||||
|
||||
|
||||
|
||||
NdfAutomata() { newState(); };
|
||||
~NdfAutomata();
|
||||
|
||||
const State* getInitial() const { return m_states[0]; };
|
||||
State* getInitial() { return m_states[0]; };
|
||||
|
||||
/// Creates a new state with a valid id
|
||||
State* newState();
|
||||
|
||||
const State* getState(int i) const { return m_states[i]; };
|
||||
size_t size() const { return m_states.size(); };
|
||||
|
||||
/// return all the symbols that lead to other states starting
|
||||
/// in any of the states in the given set. Also if there are
|
||||
/// wildcard transitions, give back a new wildcard that guarantees
|
||||
/// that its matches match all the wildcards in the set.
|
||||
/// So the symbols returned in out_symbols do NOT overlap those that
|
||||
/// match the returned wildcard (if present). And the union of out_symbols
|
||||
/// and those matched by the wildcard, are all the valid transitions from
|
||||
/// the given state set
|
||||
void symbolsFrom(const IntSet& states, SymbolSet& out_symbols,
|
||||
Wildcard*& wildcard) const;
|
||||
|
||||
/// Get the set of states that are reachable from the given state set using the given symbol
|
||||
void transitionsFrom(const IntSet& states, ustring symbol,
|
||||
IntSet& out_states) const;
|
||||
/// Get the set of states that are reachable from the given state set by wildcard
|
||||
void wildcardTransitionsFrom(const IntSet& states,
|
||||
IntSet& out_states) const;
|
||||
|
||||
/// Perform a lambda closure of a state set
|
||||
///
|
||||
/// In other words, complete the given set so it includes all the additional
|
||||
/// states that are reachable by the lambda symbol
|
||||
void lambdaClosure(IntSet& states) const;
|
||||
|
||||
/// for debugging purposes
|
||||
std::string tostr() const;
|
||||
|
||||
protected:
|
||||
/// Vector of states
|
||||
std::vector<State*> m_states;
|
||||
};
|
||||
|
||||
|
||||
@@ -177,7 +179,8 @@ class NdfAutomata {
|
||||
typedef std::vector<int> StateSetKey;
|
||||
|
||||
// Compute the unique key for the given set of states
|
||||
void keyFromStateSet(const IntSet &states, StateSetKey &out_key);
|
||||
void
|
||||
keyFromStateSet(const IntSet& states, StateSetKey& out_key);
|
||||
|
||||
|
||||
|
||||
@@ -188,84 +191,83 @@ void keyFromStateSet(const IntSet &states, StateSetKey &out_key);
|
||||
/// time parsing of light path expressions
|
||||
class DfAutomata {
|
||||
friend class DfOptimizedAutomata;
|
||||
|
||||
public:
|
||||
/// Simple state for a deterministic automata
|
||||
class State {
|
||||
friend class DfAutomata;
|
||||
friend class DfOptimizedAutomata;
|
||||
|
||||
public:
|
||||
/// Simple state for a deterministic automata
|
||||
class State {
|
||||
friend class DfAutomata;
|
||||
friend class DfOptimizedAutomata;
|
||||
public:
|
||||
State(int id)
|
||||
{
|
||||
m_id = id;
|
||||
m_wildcard_trans = -1;
|
||||
}
|
||||
|
||||
State(int id)
|
||||
{
|
||||
m_id = id;
|
||||
m_wildcard_trans = -1;
|
||||
}
|
||||
/// Get the transition for a symbol
|
||||
//
|
||||
/// Returns -1 if no transitions with that symbol. That means the
|
||||
/// symbol is not recognized at this point of the automata
|
||||
int getTransition(ustring symbol) const;
|
||||
|
||||
/// Get the transition for a symbol
|
||||
//
|
||||
/// Returns -1 if no transitions with that symbol. That means the
|
||||
/// symbol is not recognized at this point of the automata
|
||||
int getTransition(ustring symbol)const;
|
||||
// Same semantics as in NdfAutomata::State
|
||||
void addTransition(ustring symbol, State* state);
|
||||
// WARNING: this has an optimized representation and has to be called
|
||||
// always AFTER all the normal transitions have been added
|
||||
void addWildcardTransition(Wildcard* wildcard, State* state);
|
||||
|
||||
// Same semantics as in NdfAutomata::State
|
||||
void addTransition(ustring symbol, State *state);
|
||||
// WARNING: this has an optimized representation and has to be called
|
||||
// always AFTER all the normal transitions have been added
|
||||
void addWildcardTransition(Wildcard *wildcard, State *state);
|
||||
|
||||
/// Optimize transitions
|
||||
///
|
||||
/// Sometimes the existing wildcard can be extended to wrap some of
|
||||
/// the single symbol transitions. This function performs that optimization
|
||||
void removeUselessTransitions();
|
||||
|
||||
void addRule(void *rule) { m_rules.push_back(rule); };
|
||||
const RuleSet &getRules()const { return m_rules; };
|
||||
int getId()const { return m_id; };
|
||||
std::string tostr()const;
|
||||
|
||||
protected:
|
||||
|
||||
int m_id;
|
||||
// Only one transition per symbol here
|
||||
SymbolToInt m_symbol_trans;
|
||||
int m_wildcard_trans;
|
||||
// A final state here might contain several final states
|
||||
// from the original NDF automata. Therefore, we need a list
|
||||
// of rules here
|
||||
RuleSet m_rules;
|
||||
};
|
||||
|
||||
|
||||
DfAutomata() {};
|
||||
~DfAutomata();
|
||||
|
||||
State *newState();
|
||||
const State *getState(int i)const { return m_states[i]; };
|
||||
size_t size()const { return m_states.size(); };
|
||||
// In case somebody wants to reuse the same object and recreate
|
||||
// an automata, we provide this method
|
||||
void clear();
|
||||
|
||||
/// Colapse all the equivalent states into single ones
|
||||
void removeEquivalentStates();
|
||||
/// Go through all the states and perform removeUselessTransitions
|
||||
/// method call on them
|
||||
/// Optimize transitions
|
||||
///
|
||||
/// Sometimes the existing wildcard can be extended to wrap some of
|
||||
/// the single symbol transitions. This function performs that optimization
|
||||
void removeUselessTransitions();
|
||||
|
||||
/// For debuging purposes
|
||||
std::string tostr()const;
|
||||
void addRule(void* rule) { m_rules.push_back(rule); };
|
||||
const RuleSet& getRules() const { return m_rules; };
|
||||
int getId() const { return m_id; };
|
||||
std::string tostr() const;
|
||||
|
||||
protected:
|
||||
int m_id;
|
||||
// Only one transition per symbol here
|
||||
SymbolToInt m_symbol_trans;
|
||||
int m_wildcard_trans;
|
||||
// A final state here might contain several final states
|
||||
// from the original NDF automata. Therefore, we need a list
|
||||
// of rules here
|
||||
RuleSet m_rules;
|
||||
};
|
||||
|
||||
/// Return true if two states are equivalent
|
||||
///
|
||||
/// Two states are equivalent if their transition tables lead
|
||||
/// to the same states for the same symbols
|
||||
bool equivalent(const State *dfstateA, const State *dfstateB);
|
||||
|
||||
// State vector with the automata
|
||||
std::vector<State *> m_states;
|
||||
DfAutomata() {};
|
||||
~DfAutomata();
|
||||
|
||||
State* newState();
|
||||
const State* getState(int i) const { return m_states[i]; };
|
||||
size_t size() const { return m_states.size(); };
|
||||
// In case somebody wants to reuse the same object and recreate
|
||||
// an automata, we provide this method
|
||||
void clear();
|
||||
|
||||
/// Colapse all the equivalent states into single ones
|
||||
void removeEquivalentStates();
|
||||
/// Go through all the states and perform removeUselessTransitions
|
||||
/// method call on them
|
||||
void removeUselessTransitions();
|
||||
|
||||
/// For debugging purposes
|
||||
std::string tostr() const;
|
||||
|
||||
protected:
|
||||
/// Return true if two states are equivalent
|
||||
///
|
||||
/// Two states are equivalent if their transition tables lead
|
||||
/// to the same states for the same symbols
|
||||
bool equivalent(const State* dfstateA, const State* dfstateB);
|
||||
|
||||
// State vector with the automata
|
||||
std::vector<State*> m_states;
|
||||
};
|
||||
|
||||
|
||||
@@ -274,40 +276,42 @@ class DfAutomata {
|
||||
/// of state sets that have already been found to be new states of the
|
||||
/// deterministic automata
|
||||
class StateSetRecord {
|
||||
public:
|
||||
StateSetRecord(const NdfAutomata &ndfautomata, DfAutomata &dfautomata):
|
||||
m_ndfautomata(ndfautomata), m_dfautomata(dfautomata)
|
||||
{};
|
||||
public:
|
||||
StateSetRecord(const NdfAutomata& ndfautomata, DfAutomata& dfautomata)
|
||||
: m_ndfautomata(ndfautomata), m_dfautomata(dfautomata) {};
|
||||
|
||||
// A new found state is defined by the deterministic state created
|
||||
// for it and the state(int) set in the original automata
|
||||
typedef std::pair<DfAutomata::State *, IntSet> Discovery;
|
||||
// The type that will index our new created states indexed by the set key
|
||||
typedef std::map<StateSetKey, DfAutomata::State *> StateSetMap;
|
||||
// A new found state is defined by the deterministic state created
|
||||
// for it and the state(int) set in the original automata
|
||||
typedef std::pair<DfAutomata::State*, IntSet> Discovery;
|
||||
// The type that will index our new created states indexed by the set key
|
||||
typedef std::map<StateSetKey, DfAutomata::State*> StateSetMap;
|
||||
|
||||
/// Take a state set and build a new df state (or return existing one)
|
||||
/// Also, if it was newly created, append it to the discovered list so we
|
||||
/// can iterate over it later
|
||||
DfAutomata::State *ensureState(const IntSet &newstates, std::list<Discovery> &discovered);
|
||||
/// Take a state set and build a new df state (or return existing one)
|
||||
/// Also, if it was newly created, append it to the discovered list so we
|
||||
/// can iterate over it later
|
||||
DfAutomata::State* ensureState(const IntSet& newstates,
|
||||
std::list<Discovery>& discovered);
|
||||
|
||||
private:
|
||||
private:
|
||||
/// Gather all the rules from the original automata in the given sets (if any)
|
||||
/// and put them in the dfstate rule set
|
||||
void getRulesFromSet(DfAutomata::State* dfstate,
|
||||
const NdfAutomata& ndfautomata,
|
||||
const IntSet& ndfstates);
|
||||
|
||||
/// Gather all the rules from the original automata in the given sets (if any)
|
||||
/// and put them in the dfstate rule set
|
||||
void getRulesFromSet(DfAutomata::State *dfstate, const NdfAutomata &ndfautomata, const IntSet &ndfstates);
|
||||
|
||||
const NdfAutomata &m_ndfautomata;
|
||||
DfAutomata &m_dfautomata;
|
||||
StateSetMap m_key_to_dfstate;
|
||||
const NdfAutomata& m_ndfautomata;
|
||||
DfAutomata& m_dfautomata;
|
||||
StateSetMap m_key_to_dfstate;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// NDF to DF automata convertion
|
||||
/// NDF to DF automata conversion
|
||||
///
|
||||
/// This function is the most important pice of the whole process. It takes
|
||||
/// a non-deterministic finite automata and computes an equivalent deterministic
|
||||
/// one. It is equivalente in the sense that they both recognize the same language
|
||||
void ndfautoToDfauto(const NdfAutomata &ndfautomata, DfAutomata &dfautomata);
|
||||
void
|
||||
ndfautoToDfauto(const NdfAutomata& ndfautomata, DfAutomata& dfautomata);
|
||||
|
||||
OSL_NAMESPACE_EXIT
|
||||
|
||||
+426
-565
File diff suppressed because it is too large
Load Diff
+240
-187
@@ -4,15 +4,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "oslexec_pvt.h"
|
||||
using namespace OSL;
|
||||
using namespace OSL::pvt;
|
||||
|
||||
#include "runtimeoptimize.h"
|
||||
#include <OSL/llvm_util.h>
|
||||
#include "runtimeoptimize.h"
|
||||
|
||||
// additional includes for creating global OptiX variables
|
||||
#include "llvm/IR/Constants.h"
|
||||
@@ -22,7 +22,7 @@ using namespace OSL::pvt;
|
||||
|
||||
OSL_NAMESPACE_ENTER
|
||||
|
||||
namespace pvt { // OSL::pvt
|
||||
namespace pvt { // OSL::pvt
|
||||
|
||||
|
||||
|
||||
@@ -30,16 +30,16 @@ namespace pvt { // OSL::pvt
|
||||
/// code to implement a shader group.
|
||||
class BackendLLVM final : public OSOProcessorBase {
|
||||
public:
|
||||
BackendLLVM (ShadingSystemImpl &shadingsys, ShaderGroup &group,
|
||||
ShadingContext *context);
|
||||
BackendLLVM(ShadingSystemImpl& shadingsys, ShaderGroup& group,
|
||||
ShadingContext* context);
|
||||
|
||||
virtual ~BackendLLVM ();
|
||||
virtual ~BackendLLVM();
|
||||
|
||||
virtual void set_inst (int layer);
|
||||
virtual void set_inst(int layer);
|
||||
|
||||
/// Create an llvm function for the whole shader group, JIT it,
|
||||
/// and store the llvm::Function* handle to it with the ShaderGroup.
|
||||
virtual void run ();
|
||||
virtual void run();
|
||||
|
||||
|
||||
/// What LLVM debug level are we at?
|
||||
@@ -47,33 +47,33 @@ public:
|
||||
|
||||
/// Set up a bunch of static things we'll need for the whole group.
|
||||
///
|
||||
void initialize_llvm_group ();
|
||||
void initialize_llvm_group();
|
||||
|
||||
int layer_remap (int origlayer) const { return m_layer_remap[origlayer]; }
|
||||
int layer_remap(int origlayer) const { return m_layer_remap[origlayer]; }
|
||||
|
||||
/// Create an llvm function for the current shader instance.
|
||||
/// This will end up being the group entry if 'groupentry' is true.
|
||||
llvm::Function* build_llvm_instance (bool groupentry);
|
||||
llvm::Function* build_llvm_instance(bool groupentry);
|
||||
|
||||
/// Create an llvm function for group initialization code.
|
||||
llvm::Function* build_llvm_init ();
|
||||
llvm::Function* build_llvm_init();
|
||||
|
||||
/// Build up LLVM IR code for the given range [begin,end) or
|
||||
/// opcodes, putting them (initially) into basic block bb (or the
|
||||
/// current basic block if bb==NULL).
|
||||
bool build_llvm_code (int beginop, int endop, llvm::BasicBlock *bb=NULL);
|
||||
bool build_llvm_code(int beginop, int endop, llvm::BasicBlock* bb = NULL);
|
||||
|
||||
typedef std::map<std::string, llvm::Value*> AllocationMap;
|
||||
|
||||
void llvm_assign_initial_value (const Symbol& sym, bool force = false);
|
||||
llvm::LLVMContext &llvm_context () const { return ll.context(); }
|
||||
AllocationMap &named_values () { return m_named_values; }
|
||||
void llvm_assign_initial_value(const Symbol& sym, bool force = false);
|
||||
llvm::LLVMContext& llvm_context() const { return ll.context(); }
|
||||
AllocationMap& named_values() { return m_named_values; }
|
||||
|
||||
/// Return an llvm::Value* corresponding to the address of the given
|
||||
/// symbol element, with derivative (0=value, 1=dx, 2=dy) and array
|
||||
/// index (NULL if it's not an array).
|
||||
llvm::Value *llvm_get_pointer (const Symbol& sym, int deriv=0,
|
||||
llvm::Value *arrayindex=NULL);
|
||||
llvm::Value* llvm_get_pointer(const Symbol& sym, int deriv = 0,
|
||||
llvm::Value* arrayindex = NULL);
|
||||
|
||||
/// Return the llvm::Value* corresponding to the given element
|
||||
/// value, with derivative (0=value, 1=dx, 2=dy), array index (NULL
|
||||
@@ -83,9 +83,9 @@ public:
|
||||
/// return the scalar -- this allows automatic casting to triples.
|
||||
/// Finally, auto-cast int<->float if requested (no conversion is
|
||||
/// performed if cast is the default of UNKNOWN).
|
||||
llvm::Value *llvm_load_value (const Symbol& sym, int deriv,
|
||||
llvm::Value *arrayindex, int component,
|
||||
TypeDesc cast=TypeDesc::UNKNOWN);
|
||||
llvm::Value* llvm_load_value(const Symbol& sym, int deriv,
|
||||
llvm::Value* arrayindex, int component,
|
||||
TypeDesc cast = TypeDesc::UNKNOWN);
|
||||
|
||||
|
||||
/// Given an llvm::Value* of a pointer (and the type of the data
|
||||
@@ -97,62 +97,71 @@ public:
|
||||
/// and it's a scalar, return the scalar -- this allows automatic
|
||||
/// casting to triples. Finally, auto-cast int<->float if requested
|
||||
/// (no conversion is performed if cast is the default of UNKNOWN).
|
||||
llvm::Value *llvm_load_value (llvm::Value *ptr, const TypeSpec &type,
|
||||
int deriv, llvm::Value *arrayindex,
|
||||
int component, TypeDesc cast=TypeDesc::UNKNOWN);
|
||||
llvm::Value* llvm_load_value(llvm::Value* ptr, const TypeSpec& type,
|
||||
int deriv, llvm::Value* arrayindex,
|
||||
int component,
|
||||
TypeDesc cast = TypeDesc::UNKNOWN,
|
||||
const std::string& llname = {});
|
||||
|
||||
/// Just like llvm_load_value, but when both the symbol and the
|
||||
/// array index are known to be constants. This can even handle
|
||||
/// pulling constant-indexed elements out of constant arrays. Use
|
||||
/// arrayindex==-1 to indicate that it's not an array dereference.
|
||||
llvm::Value *llvm_load_constant_value (const Symbol& sym,
|
||||
int arrayindex, int component,
|
||||
TypeDesc cast=TypeDesc::UNKNOWN);
|
||||
llvm::Value* llvm_load_constant_value(const Symbol& sym, int arrayindex,
|
||||
int component,
|
||||
TypeDesc cast = TypeDesc::UNKNOWN);
|
||||
|
||||
/// llvm_load_value with non-constant component designation. Does
|
||||
/// not work with arrays or do type casts!
|
||||
llvm::Value *llvm_load_component_value (const Symbol& sym, int deriv,
|
||||
llvm::Value *component);
|
||||
llvm::Value* llvm_load_component_value(const Symbol& sym, int deriv,
|
||||
llvm::Value* component);
|
||||
|
||||
/// Non-array version of llvm_load_value, with default deriv &
|
||||
/// component.
|
||||
llvm::Value *llvm_load_value (const Symbol& sym, int deriv = 0,
|
||||
int component = 0,
|
||||
TypeDesc cast=TypeDesc::UNKNOWN) {
|
||||
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);
|
||||
llvm::Value* llvm_load_value(const Symbol& sym, int deriv = 0,
|
||||
int component = 0,
|
||||
TypeDesc cast = TypeDesc::UNKNOWN)
|
||||
{
|
||||
return 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) {
|
||||
llvm::Value* llvm_load_string(const Symbol& sym)
|
||||
{
|
||||
OSL_DASSERT(sym.typespec().is_string());
|
||||
return use_optix()
|
||||
? llvm_load_device_string(sym, /*follow*/ true)
|
||||
: llvm_load_value(sym);
|
||||
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));
|
||||
}
|
||||
|
||||
/// Legacy version
|
||||
///
|
||||
llvm::Value *loadLLVMValue (const Symbol& sym, int component=0,
|
||||
int deriv=0, TypeDesc cast=TypeDesc::UNKNOWN) {
|
||||
return llvm_load_value (sym, deriv, NULL, component, cast);
|
||||
llvm::Value* loadLLVMValue(const Symbol& sym, int component = 0,
|
||||
int deriv = 0, TypeDesc cast = TypeDesc::UNKNOWN)
|
||||
{
|
||||
return llvm_load_value(sym, deriv, NULL, component, cast);
|
||||
}
|
||||
|
||||
/// 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);
|
||||
/// 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.
|
||||
llvm::Value* llvm_load_arg(const Symbol& sym, bool derivs);
|
||||
|
||||
/// Just like llvm_load_arg(sym,deriv), except use use sym's derivs
|
||||
/// as-is, no coercion.
|
||||
llvm::Value *llvm_load_arg (const Symbol& sym) {
|
||||
return llvm_load_arg (sym, sym.has_derivs());
|
||||
llvm::Value* llvm_load_arg(const Symbol& sym)
|
||||
{
|
||||
return llvm_load_arg(sym, sym.has_derivs());
|
||||
}
|
||||
|
||||
/// Store new_val into the given symbol, given the derivative
|
||||
@@ -161,8 +170,8 @@ public:
|
||||
/// symbol doesn't have a deriv, it's a nop. If the component >0
|
||||
/// and it's a scalar, set the scalar. Returns true if ok, false
|
||||
/// upon failure.
|
||||
bool llvm_store_value (llvm::Value *new_val, const Symbol& sym, int deriv,
|
||||
llvm::Value *arrayindex, int component);
|
||||
bool llvm_store_value(llvm::Value* new_val, const Symbol& sym, int deriv,
|
||||
llvm::Value* arrayindex, int component);
|
||||
|
||||
/// Store new_val into the memory pointed to by dst_ptr, given the
|
||||
/// derivative (0=value, 1=dx, 2=dy), array index (NULL if it's not
|
||||
@@ -170,150 +179,160 @@ public:
|
||||
/// and the symbol doesn't have a deriv, it's a nop. If the
|
||||
/// component >0 and it's a scalar, set the scalar. Returns true if
|
||||
/// ok, false upon failure.
|
||||
bool llvm_store_value (llvm::Value* new_val, llvm::Value* dst_ptr,
|
||||
const TypeSpec &type, int deriv,
|
||||
llvm::Value* arrayindex, int component);
|
||||
bool llvm_store_value(llvm::Value* new_val, llvm::Value* dst_ptr,
|
||||
const TypeSpec& type, int deriv,
|
||||
llvm::Value* arrayindex, int component);
|
||||
|
||||
/// Non-array version of llvm_store_value, with default deriv &
|
||||
/// component.
|
||||
bool llvm_store_value (llvm::Value *new_val, const Symbol& sym,
|
||||
int deriv=0, int component=0) {
|
||||
return llvm_store_value (new_val, sym, deriv, NULL, component);
|
||||
bool llvm_store_value(llvm::Value* new_val, const Symbol& sym,
|
||||
int deriv = 0, int component = 0)
|
||||
{
|
||||
return llvm_store_value(new_val, sym, deriv, NULL, component);
|
||||
}
|
||||
|
||||
/// llvm_store_value with non-constant component designation. Does
|
||||
/// not work with arrays or do type casts!
|
||||
bool llvm_store_component_value (llvm::Value *new_val, const Symbol& sym,
|
||||
int deriv, llvm::Value *component);
|
||||
bool llvm_store_component_value(llvm::Value* new_val, const Symbol& sym,
|
||||
int deriv, llvm::Value* component);
|
||||
|
||||
/// Legacy version
|
||||
///
|
||||
bool storeLLVMValue (llvm::Value* new_val, const Symbol& sym,
|
||||
int component=0, int deriv=0) {
|
||||
return llvm_store_value (new_val, sym, deriv, component);
|
||||
bool storeLLVMValue(llvm::Value* new_val, const Symbol& sym,
|
||||
int component = 0, int deriv = 0)
|
||||
{
|
||||
return llvm_store_value(new_val, sym, deriv, component);
|
||||
}
|
||||
|
||||
/// Generate an alloca instruction to allocate space for the given
|
||||
/// type, with derivs if derivs==true, and return the its pointer.
|
||||
llvm::Value *llvm_alloca (const TypeSpec &type, bool derivs,
|
||||
const std::string &name="", int align=0);
|
||||
llvm::Value* llvm_alloca(const TypeSpec& type, bool derivs,
|
||||
const std::string& name = "", int align = 0);
|
||||
|
||||
/// Given the OSL symbol, return the llvm::Value* corresponding to the
|
||||
/// address of the start of that symbol (first element, first component,
|
||||
/// and just the plain value if it has derivatives). This is retrieved
|
||||
/// from the allocation map if already there; and if not yet in the
|
||||
/// map, the symbol is alloca'd and placed in the map.
|
||||
llvm::Value *getOrAllocateLLVMSymbol (const Symbol& sym);
|
||||
llvm::Value* getOrAllocateLLVMSymbol(const Symbol& sym);
|
||||
|
||||
/// Allocate a CUDA variable for the given OSL symbol and return a pointer
|
||||
/// to the corresponding LLVM GlobalVariable, or return the pointer if it
|
||||
/// has already been allocated.
|
||||
llvm::Value *getOrAllocateCUDAVariable (const Symbol& sym, bool addMetadata=false);
|
||||
llvm::Value* getOrAllocateCUDAVariable(const Symbol& sym);
|
||||
|
||||
/// Create a CUDA global variable and add it to the current Module
|
||||
llvm::Value *addCUDAVariable (const std::string& name, int size, int alignment,
|
||||
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 );
|
||||
/// 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);
|
||||
|
||||
/// Retrieve an llvm::Value that is a pointer holding the start address
|
||||
/// of the specified symbol. This always works for globals and params;
|
||||
/// for stack variables (locals/temps) is succeeds only if the symbol is
|
||||
/// already in the allocation table (will fail otherwise). This method
|
||||
/// is not designed to retrieve constants.
|
||||
llvm::Value *getLLVMSymbolBase (const Symbol &sym);
|
||||
llvm::Value* getLLVMSymbolBase(const Symbol& sym);
|
||||
|
||||
/// Retrieve the named global ("P", "N", etc.).
|
||||
llvm::Value *llvm_global_symbol_ptr (ustring name);
|
||||
llvm::Value* llvm_global_symbol_ptr(ustring name);
|
||||
|
||||
/// Test whether val is nonzero, return the llvm::Value* that's the
|
||||
/// result of a CreateICmpNE or CreateFCmpUNE (depending on the
|
||||
/// type). If test_derivs is true, it it also tests whether the
|
||||
/// derivs are zero.
|
||||
llvm::Value *llvm_test_nonzero (Symbol &val, bool test_derivs = false);
|
||||
llvm::Value* llvm_test_nonzero(Symbol& val, bool test_derivs = false);
|
||||
|
||||
/// Implementaiton of Simple assignment. If arrayindex >= 0, in
|
||||
/// Implementation of Simple assignment. If arrayindex >= 0, in
|
||||
/// designates a particular array index to assign.
|
||||
bool llvm_assign_impl (Symbol &Result, Symbol &Src, int arrayindex = -1,
|
||||
int srccomp = -1, int dstcomp = -1);
|
||||
bool llvm_assign_impl(Symbol& Result, Symbol& Src, int arrayindex = -1,
|
||||
int srccomp = -1, int dstcomp = -1);
|
||||
|
||||
|
||||
/// Convert the name of a global (and its derivative index) into the
|
||||
/// field number of the ShaderGlobals struct.
|
||||
int ShaderGlobalNameToIndex (ustring name);
|
||||
int ShaderGlobalNameToIndex(ustring name);
|
||||
|
||||
/// Return the LLVM type handle for the ShaderGlobals struct.
|
||||
///
|
||||
llvm::Type *llvm_type_sg ();
|
||||
llvm::Type* llvm_type_sg();
|
||||
|
||||
/// Return the LLVM type handle for a pointer to a
|
||||
/// ShaderGlobals struct.
|
||||
llvm::Type *llvm_type_sg_ptr ();
|
||||
llvm::Type* llvm_type_sg_ptr();
|
||||
|
||||
/// Return the ShaderGlobals pointer.
|
||||
///
|
||||
llvm::Value *sg_ptr () const { return m_llvm_shaderglobals_ptr; }
|
||||
llvm::Value* sg_ptr() const { return m_llvm_shaderglobals_ptr; }
|
||||
|
||||
llvm::Type *llvm_type_closure_component ();
|
||||
llvm::Type *llvm_type_closure_component_ptr ();
|
||||
llvm::Type* llvm_type_closure_component();
|
||||
llvm::Type* llvm_type_closure_component_ptr();
|
||||
|
||||
/// Return the ShaderGlobals pointer cast as a void*.
|
||||
///
|
||||
llvm::Value *sg_void_ptr () {
|
||||
return ll.void_ptr (m_llvm_shaderglobals_ptr);
|
||||
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 = {})
|
||||
{
|
||||
return ll.ptr_cast(val, type.simpletype(), llname);
|
||||
}
|
||||
|
||||
llvm::Value *llvm_ptr_cast (llvm::Value* val, const TypeSpec &type) {
|
||||
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));
|
||||
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 the LLVM type handle for a structure of the common group
|
||||
/// data that holds all the shader params.
|
||||
llvm::Type *llvm_type_groupdata ();
|
||||
llvm::Type* llvm_type_groupdata();
|
||||
|
||||
/// Return the LLVM type handle for a pointer to the common group
|
||||
/// data that holds all the shader params.
|
||||
llvm::Type *llvm_type_groupdata_ptr ();
|
||||
llvm::Type* llvm_type_groupdata_ptr();
|
||||
|
||||
/// Return the group data pointer.
|
||||
///
|
||||
llvm::Value *groupdata_ptr () const { return m_llvm_groupdata_ptr; }
|
||||
llvm::Value* groupdata_ptr() const { return m_llvm_groupdata_ptr; }
|
||||
|
||||
/// Return the group data pointer cast as a void*.
|
||||
///
|
||||
llvm::Value *groupdata_void_ptr () {
|
||||
return ll.void_ptr (m_llvm_groupdata_ptr);
|
||||
llvm::Value* groupdata_void_ptr()
|
||||
{
|
||||
return ll.void_ptr(m_llvm_groupdata_ptr);
|
||||
}
|
||||
|
||||
/// Return a reference to the specified field within the group data.
|
||||
llvm::Value *groupdata_field_ref (int fieldnum);
|
||||
llvm::Value* groupdata_field_ref(int fieldnum);
|
||||
|
||||
/// Return a pointer to the specified field within the group data,
|
||||
/// optionally cast to pointer to a particular data type.
|
||||
llvm::Value *groupdata_field_ptr (int fieldnum,
|
||||
TypeDesc type = TypeDesc::UNKNOWN);
|
||||
llvm::Value* groupdata_field_ptr(int fieldnum,
|
||||
TypeDesc type = TypeDesc::UNKNOWN);
|
||||
|
||||
/// Return the userdata base pointer.
|
||||
llvm::Value *userdata_base_ptr () const { return m_llvm_userdata_base_ptr; }
|
||||
llvm::Value* userdata_base_ptr() const { return m_llvm_userdata_base_ptr; }
|
||||
|
||||
/// Return the output base pointer.
|
||||
llvm::Value *output_base_ptr () const { return m_llvm_output_base_ptr; }
|
||||
llvm::Value* output_base_ptr() const { return m_llvm_output_base_ptr; }
|
||||
|
||||
/// Return the shade index
|
||||
llvm::Value *shadeindex () const { return m_llvm_shadeindex; }
|
||||
llvm::Value* shadeindex() const { return m_llvm_shadeindex; }
|
||||
|
||||
// For a symloc, compute the llvm::Value of the pointer to its true,
|
||||
// offset location from the base pointer for shade index `sindex`
|
||||
// (which should already be a i64, or if nullptr, then use
|
||||
// m_llvm_shadeindex and convert it to i64).
|
||||
llvm::Value *symloc_ptr(const SymLocationDesc* symloc,
|
||||
llvm::Value* symloc_ptr(const SymLocationDesc* symloc,
|
||||
llvm::Value* base_ptr,
|
||||
llvm::Value* sindex = nullptr) {
|
||||
llvm::Value* sindex = nullptr)
|
||||
{
|
||||
llvm::Value* offset = ll.constanti64(symloc->offset);
|
||||
llvm::Value* stride = ll.constanti64(symloc->stride);
|
||||
if (!sindex)
|
||||
@@ -324,47 +343,47 @@ public:
|
||||
|
||||
/// Return a ref to the bool where the "layer_run" flag is stored for
|
||||
/// the specified layer.
|
||||
llvm::Value *layer_run_ref (int layer);
|
||||
llvm::Value* layer_run_ref(int layer);
|
||||
|
||||
/// Return a ref to the bool where the "userdata_initialized" flag is
|
||||
/// stored for the specified userdata index.
|
||||
llvm::Value *userdata_initialized_ref (int userdata_index=0);
|
||||
llvm::Value* userdata_initialized_ref(int userdata_index = 0);
|
||||
|
||||
/// Generate LLVM code to zero out the variable (including derivs)
|
||||
///
|
||||
void llvm_assign_zero (const Symbol &sym);
|
||||
void llvm_assign_zero(const Symbol& sym);
|
||||
|
||||
/// Generate LLVM code to zero out the derivatives of sym.
|
||||
///
|
||||
void llvm_zero_derivs (const Symbol &sym);
|
||||
void llvm_zero_derivs(const Symbol& sym);
|
||||
|
||||
/// Generate LLVM code to zero out the derivatives of an array
|
||||
/// only for the first count elements of it.
|
||||
///
|
||||
void llvm_zero_derivs (const Symbol &sym, llvm::Value *count);
|
||||
void llvm_zero_derivs(const Symbol& sym, llvm::Value* count);
|
||||
|
||||
/// Generate a debugging printf at shader execution time.
|
||||
void llvm_gen_debug_printf (string_view message);
|
||||
void llvm_gen_debug_printf(string_view message);
|
||||
|
||||
/// Generate a warning message at shader execution time.
|
||||
void llvm_gen_warning (string_view message);
|
||||
void llvm_gen_warning(string_view message);
|
||||
|
||||
/// Generate an error message at shader execution time.
|
||||
void llvm_gen_error (string_view message);
|
||||
void llvm_gen_error(string_view message);
|
||||
|
||||
/// Generate code to call the given layer. If 'unconditional' is
|
||||
/// true, call it without even testing if the layer has already been
|
||||
/// called.
|
||||
void llvm_call_layer (int layer, bool unconditional = false);
|
||||
void llvm_call_layer(int layer, bool unconditional = false);
|
||||
|
||||
/// Execute the upstream connection (if any, and if not yet run) that
|
||||
/// establishes the value of symbol sym, which has index 'symindex'
|
||||
/// within the current layer rop.inst(). If already_run is not NULL,
|
||||
/// it points to a vector of layer indices that are known to have been
|
||||
/// it points to a vector of layer indices that are known to have been
|
||||
/// run -- those can be skipped without dynamically checking their
|
||||
/// execution status.
|
||||
void llvm_run_connected_layers (Symbol &sym, int symindex, int opnum = -1,
|
||||
std::set<int> *already_run = NULL);
|
||||
void llvm_run_connected_layers(Symbol& sym, int symindex, int opnum = -1,
|
||||
std::set<int>* already_run = NULL);
|
||||
|
||||
/// Generate code for a call to the named function with the given
|
||||
/// arg list as symbols -- float & ints will be passed by value,
|
||||
@@ -372,127 +391,161 @@ public:
|
||||
/// is true, pass pointers even for floats if they have derivs.
|
||||
/// Return an llvm::Value* corresponding to the return value of the
|
||||
/// function, if any.
|
||||
llvm::Value *llvm_call_function (const char *name, cspan<const Symbol *> args,
|
||||
bool deriv_ptrs=false);
|
||||
llvm::Value *llvm_call_function (const char *name, const Symbol &A,
|
||||
bool deriv_ptrs=false) {
|
||||
return llvm_call_function (name, { &A }, deriv_ptrs);
|
||||
llvm::Value* llvm_call_function(const char* name, cspan<const Symbol*> args,
|
||||
bool deriv_ptrs = false);
|
||||
llvm::Value* llvm_call_function(const char* name, const Symbol& A,
|
||||
bool deriv_ptrs = false)
|
||||
{
|
||||
return llvm_call_function(name, { &A }, deriv_ptrs);
|
||||
}
|
||||
llvm::Value *llvm_call_function (const char *name, const Symbol &A,
|
||||
const Symbol &B, bool deriv_ptrs=false) {
|
||||
return llvm_call_function (name, { &A, &B }, deriv_ptrs);
|
||||
llvm::Value* llvm_call_function(const char* name, const Symbol& A,
|
||||
const Symbol& B, bool deriv_ptrs = false)
|
||||
{
|
||||
return llvm_call_function(name, { &A, &B }, deriv_ptrs);
|
||||
}
|
||||
llvm::Value *llvm_call_function (const char *name, const Symbol &A,
|
||||
const Symbol &B, const Symbol &C,
|
||||
bool deriv_ptrs=false) {
|
||||
return llvm_call_function (name, { &A, &B, &C }, deriv_ptrs);
|
||||
llvm::Value* llvm_call_function(const char* name, const Symbol& A,
|
||||
const Symbol& B, const Symbol& C,
|
||||
bool deriv_ptrs = false)
|
||||
{
|
||||
return llvm_call_function(name, { &A, &B, &C }, deriv_ptrs);
|
||||
}
|
||||
|
||||
TypeDesc llvm_typedesc (const TypeSpec &typespec) {
|
||||
return typespec.is_closure_based()
|
||||
? TypeDesc(TypeDesc::PTR, typespec.arraylength())
|
||||
: typespec.simpletype();
|
||||
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();
|
||||
}
|
||||
|
||||
/// Generate the appropriate llvm type definition for a TypeSpec
|
||||
/// (this is the actual type, for example when we allocate it).
|
||||
/// Allocates ptrs for closures.
|
||||
llvm::Type *llvm_type (const TypeSpec &typespec) {
|
||||
return ll.llvm_type (llvm_typedesc(typespec));
|
||||
llvm::Type* llvm_type(const TypeSpec& typespec)
|
||||
{
|
||||
return ll.llvm_type(llvm_typedesc(typespec));
|
||||
}
|
||||
|
||||
/// Generate the parameter-passing llvm type definition for an OSL
|
||||
/// TypeSpec.
|
||||
llvm::Type *llvm_pass_type (const TypeSpec &typespec);
|
||||
llvm::Type* llvm_pass_type(const TypeSpec& typespec);
|
||||
|
||||
llvm::PointerType *llvm_type_prepare_closure_func() { return m_llvm_type_prepare_closure_func; }
|
||||
llvm::PointerType *llvm_type_setup_closure_func() { return m_llvm_type_setup_closure_func; }
|
||||
|
||||
/// Return the basic block of the exit for the whole instance.
|
||||
///
|
||||
bool llvm_has_exit_instance_block () const {
|
||||
return m_exit_instance_block;
|
||||
llvm::PointerType* llvm_type_prepare_closure_func()
|
||||
{
|
||||
return m_llvm_type_prepare_closure_func;
|
||||
}
|
||||
llvm::PointerType* llvm_type_setup_closure_func()
|
||||
{
|
||||
return m_llvm_type_setup_closure_func;
|
||||
}
|
||||
|
||||
/// Return the basic block of the exit for the whole instance.
|
||||
///
|
||||
llvm::BasicBlock *llvm_exit_instance_block () {
|
||||
if (! m_exit_instance_block) {
|
||||
std::string name = Strutil::sprintf ("%s_%d_exit_", inst()->layername(), inst()->id());
|
||||
m_exit_instance_block = ll.new_basic_block (name);
|
||||
bool llvm_has_exit_instance_block() const { return m_exit_instance_block; }
|
||||
|
||||
/// Return the basic block of the exit for the whole instance.
|
||||
///
|
||||
llvm::BasicBlock* llvm_exit_instance_block()
|
||||
{
|
||||
if (!m_exit_instance_block) {
|
||||
std::string name = llnamefmt("{}_{}_exit_", inst()->layername(),
|
||||
inst()->id());
|
||||
m_exit_instance_block = ll.new_basic_block(name);
|
||||
}
|
||||
return m_exit_instance_block;
|
||||
}
|
||||
|
||||
/// Check for inf/nan in all written-to arguments of the op
|
||||
void llvm_generate_debugnan (const Opcode &op);
|
||||
void llvm_generate_debugnan(const Opcode& op);
|
||||
/// Check for uninitialized values in all read-from arguments to the op
|
||||
void llvm_generate_debug_uninit (const Opcode &op);
|
||||
void llvm_generate_debug_uninit(const Opcode& op);
|
||||
/// Print debugging line for the op
|
||||
void llvm_generate_debug_op_printf (const Opcode &op);
|
||||
void llvm_generate_debug_op_printf(const Opcode& op);
|
||||
|
||||
llvm::Function *layer_func () const { return ll.current_function(); }
|
||||
llvm::Function* layer_func() const { return ll.current_function(); }
|
||||
|
||||
/// Call this when JITing a texture-like call, to track how many.
|
||||
void generated_texture_call (bool handle) {
|
||||
void generated_texture_call(bool handle)
|
||||
{
|
||||
shadingsys().m_stat_tex_calls_codegened += 1;
|
||||
if (handle)
|
||||
shadingsys().m_stat_tex_calls_as_handles += 1;
|
||||
}
|
||||
|
||||
/// Return the mapping from symbol names to GlobalVariables.
|
||||
std::map<std::string,llvm::GlobalVariable*>& get_const_map() { return m_const_map; }
|
||||
std::map<std::string, llvm::GlobalVariable*>& get_const_map()
|
||||
{
|
||||
return m_const_map;
|
||||
}
|
||||
|
||||
/// Return whether or not we are compiling for an OptiX-based renderer.
|
||||
bool use_optix() { return m_use_optix; }
|
||||
|
||||
/// Return if we should compile against free function versions of Renderer Service.
|
||||
bool use_rs_bitcode() { return m_use_rs_bitcode; }
|
||||
|
||||
/// Return the userdata index for the given Symbol. Return -1 if the Symbol
|
||||
/// is not an input parameter or is constant and therefore doesn't have an
|
||||
/// entry in the groupdata struct.
|
||||
int find_userdata_index (const Symbol& sym);
|
||||
int find_userdata_index(const Symbol& sym);
|
||||
|
||||
LLVM_Util ll;
|
||||
|
||||
private:
|
||||
std::vector<int> m_layer_remap; ///< Remapping of layer ordering
|
||||
std::set<int> m_layers_already_run; ///< List of layers run
|
||||
int m_num_used_layers; ///< Number of layers actually used
|
||||
// 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();
|
||||
}
|
||||
|
||||
double m_stat_total_llvm_time; ///< total time spent on LLVM
|
||||
double m_stat_llvm_setup_time; ///< llvm setup time
|
||||
double m_stat_llvm_irgen_time; ///< llvm IR generation time
|
||||
double m_stat_llvm_opt_time; ///< llvm IR optimization time
|
||||
double m_stat_llvm_jit_time; ///< llvm JIT time
|
||||
private:
|
||||
std::vector<int> m_layer_remap; ///< Remapping of layer ordering
|
||||
std::set<int> m_layers_already_run; ///< List of layers run
|
||||
int m_num_used_layers; ///< Number of layers actually used
|
||||
|
||||
double m_stat_total_llvm_time; ///< total time spent on LLVM
|
||||
double m_stat_llvm_setup_time; ///< llvm setup time
|
||||
double m_stat_llvm_irgen_time; ///< llvm IR generation time
|
||||
double m_stat_llvm_opt_time; ///< llvm IR optimization time
|
||||
double m_stat_llvm_jit_time; ///< llvm JIT time
|
||||
|
||||
// LLVM stuff
|
||||
AllocationMap m_named_values;
|
||||
std::map<const Symbol*,int> m_param_order_map;
|
||||
llvm::Value *m_llvm_shaderglobals_ptr;
|
||||
llvm::Value *m_llvm_groupdata_ptr;
|
||||
llvm::Value *m_llvm_userdata_base_ptr;
|
||||
llvm::Value *m_llvm_output_base_ptr;
|
||||
llvm::Value *m_llvm_shadeindex;
|
||||
llvm::BasicBlock * m_exit_instance_block; // exit point for the instance
|
||||
llvm::Type *m_llvm_type_sg; // LLVM type of ShaderGlobals struct
|
||||
llvm::Type *m_llvm_type_groupdata; // LLVM type of group data
|
||||
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
|
||||
std::map<const Symbol*, int> m_param_order_map;
|
||||
llvm::Value* m_llvm_shaderglobals_ptr;
|
||||
llvm::Value* m_llvm_groupdata_ptr;
|
||||
llvm::Value* m_llvm_userdata_base_ptr;
|
||||
llvm::Value* m_llvm_output_base_ptr;
|
||||
llvm::Value* m_llvm_shadeindex;
|
||||
llvm::BasicBlock* m_exit_instance_block; // exit point for the instance
|
||||
llvm::Type* m_llvm_type_sg; // LLVM type of ShaderGlobals struct
|
||||
llvm::Type* m_llvm_type_groupdata; // LLVM type of group data
|
||||
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
|
||||
|
||||
// A mapping from symbol names to llvm::GlobalVariables
|
||||
std::map<std::string,llvm::GlobalVariable*> m_const_map;
|
||||
std::map<std::string, llvm::GlobalVariable*> m_const_map;
|
||||
|
||||
// A mapping from canonical strings to string variable names, used to
|
||||
// detect collisions that might occur due to using the string hash to
|
||||
// create variable names.
|
||||
std::map<std::string,std::string> m_varname_map;
|
||||
// Name of each indexed field in the groupdata, mostly for debugging.
|
||||
std::vector<std::string> m_groupdata_field_names;
|
||||
|
||||
bool m_use_optix; ///< Compile for OptiX?
|
||||
bool m_use_optix; ///< Compile for OptiX?
|
||||
bool m_use_rs_bitcode; /// To use free function versions of Renderer Service functions.
|
||||
|
||||
friend class ShadingSystemImpl;
|
||||
};
|
||||
|
||||
|
||||
}; // namespace pvt
|
||||
}; // namespace pvt
|
||||
OSL_NAMESPACE_EXIT
|
||||
|
||||
@@ -35,6 +35,7 @@ static ustring op_and("and");
|
||||
static ustring op_backfacing("backfacing");
|
||||
static ustring op_break("break");
|
||||
static ustring op_calculatenormal("calculatenormal");
|
||||
static ustring op_closure("closure");
|
||||
static ustring op_compl("compl");
|
||||
static ustring op_concat("concat");
|
||||
static ustring op_continue("continue");
|
||||
@@ -101,23 +102,25 @@ is_shader_global_uniform_by_name(ustring name);
|
||||
|
||||
namespace // Unnamed
|
||||
{
|
||||
|
||||
// Even when all inputs to an operation are uniform,
|
||||
// the results written to output symbols maybe varying.
|
||||
bool
|
||||
are_op_results_always_implicitly_varying(ustring opname)
|
||||
{
|
||||
return (opname == Strings::op_getmessage) | (opname == Strings::op_trace)
|
||||
| (opname == Strings::op_texture)
|
||||
| (opname == Strings::op_texture3d)
|
||||
| (opname == Strings::op_texture) | (opname == Strings::op_texture3d)
|
||||
| (opname == Strings::op_pointcloud_search)
|
||||
| (opname == Strings::op_pointcloud_get)
|
||||
| (opname == Strings::op_pointcloud_write);
|
||||
| (opname == Strings::op_pointcloud_write)
|
||||
| (opname == Strings::op_closure);
|
||||
// Renderer might identify result of getattribute as always uniform
|
||||
// depending on the attribute itself, so it cannot
|
||||
// be "always" implicitly varying based solely on the opname.
|
||||
// We consider getattribute during discovery.
|
||||
}
|
||||
|
||||
|
||||
// Even when all inputs to an operation are varying,
|
||||
// the results written to output symbols maybe uniform.
|
||||
bool
|
||||
@@ -166,6 +169,8 @@ does_op_implementation_require_masking(ustring opname)
|
||||
return lazy_lookup.find(opname) != lazy_lookup.end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Create some placeholder symbols for shader globals that have don't
|
||||
// normally have symbols.
|
||||
// Purpose is to allow our data structures to use Symbol * as a key
|
||||
@@ -180,7 +185,7 @@ struct Symbols4ProtectedShaderGlobals {
|
||||
|
||||
SymbolPtrVec varying_symbols;
|
||||
|
||||
void check_if_varing(Symbol& s)
|
||||
void check_if_varying(Symbol& s)
|
||||
{
|
||||
if (!is_shader_global_uniform_by_name(s.name())) {
|
||||
s.make_varying();
|
||||
@@ -197,16 +202,18 @@ struct Symbols4ProtectedShaderGlobals {
|
||||
, surfacearea(Strings::op_surfacearea, TypeSpec(), SymTypeGlobal)
|
||||
, time(Strings::time, TypeSpec(), SymTypeGlobal)
|
||||
{
|
||||
check_if_varing(shader2common);
|
||||
check_if_varing(object2common);
|
||||
check_if_varing(flipHandedness);
|
||||
check_if_varing(raytype);
|
||||
check_if_varing(backfacing);
|
||||
check_if_varing(surfacearea);
|
||||
check_if_varing(time);
|
||||
check_if_varying(shader2common);
|
||||
check_if_varying(object2common);
|
||||
check_if_varying(flipHandedness);
|
||||
check_if_varying(raytype);
|
||||
check_if_varying(backfacing);
|
||||
check_if_varying(surfacearea);
|
||||
check_if_varying(time);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
Symbols4ProtectedShaderGlobals&
|
||||
psg()
|
||||
{
|
||||
@@ -233,8 +240,7 @@ private:
|
||||
static constexpr OpcodeTest no_test = nullptr;
|
||||
|
||||
// Map opcode names to a Dependency info
|
||||
std::unordered_map<ustring, Dependency, ustringHash> m_lookup;
|
||||
|
||||
std::unordered_map<ustring, Dependency> m_lookup;
|
||||
|
||||
/// Return the ptr to the symbol that is the argnum-th argument to the
|
||||
/// given op in the instance.
|
||||
@@ -259,8 +265,8 @@ private:
|
||||
// We can know all the space names at this time
|
||||
ustring from = From ? *((ustring*)From->data())
|
||||
: Strings::common;
|
||||
ustring to = *((ustring*)To->data());
|
||||
ustring syn = inst.shadingsys().commonspace_synonym();
|
||||
ustring to = *((ustring*)To->data());
|
||||
ustring syn = inst.shadingsys().commonspace_synonym();
|
||||
if (from == syn)
|
||||
from = Strings::common;
|
||||
if (to == syn)
|
||||
@@ -355,6 +361,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static SymbolPtrVec*
|
||||
protected_shader_globals_op_implicitly_depends_on(ShaderInstance& inst,
|
||||
Opcode& opcode)
|
||||
@@ -363,17 +371,20 @@ protected_shader_globals_op_implicitly_depends_on(ShaderInstance& inst,
|
||||
return lazyDependencies.lookup(inst, opcode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
is_op_result_always_logically_boolean(ustring opname)
|
||||
{
|
||||
// Test if explicit comparison is faster or not
|
||||
static boost::container::flat_set<ustring> lazy_lookup(
|
||||
{ Strings::op_getattribute, Strings::op_eq,
|
||||
Strings::op_ge, Strings::op_gt, Strings::op_le, Strings::op_lt,
|
||||
Strings::op_neq, Strings::op_and, Strings::op_or });
|
||||
{ Strings::op_getattribute, Strings::op_eq, Strings::op_ge,
|
||||
Strings::op_gt, Strings::op_le, Strings::op_lt, Strings::op_neq,
|
||||
Strings::op_and, Strings::op_or });
|
||||
return lazy_lookup.find(opname) != lazy_lookup.end();
|
||||
}
|
||||
|
||||
|
||||
// TODO: Add more analysis to identify boolean results from the class of
|
||||
// operations who would produce a boolean result if given boolean inputs.
|
||||
// For example complement (~) would have a boolean result when passed a
|
||||
@@ -383,7 +394,8 @@ is_op_result_always_logically_boolean(ustring opname)
|
||||
// comparison operators even if the are not "currently"
|
||||
// being referenced. May need to disable some warnings
|
||||
// error #177: function "..." was declared but never referenced
|
||||
OSL_INTEL_PRAGMA(warning ( disable:177 ))
|
||||
OSL_INTEL_PRAGMA(warning(disable : 177))
|
||||
|
||||
|
||||
// The Position returned by top_pos changes and symbols are pushed and popped.
|
||||
// However any given position is invariant as scopes change, and one
|
||||
@@ -443,7 +455,6 @@ public:
|
||||
|
||||
DependencyTreeTracker(const DependencyTreeTracker&) = delete;
|
||||
|
||||
|
||||
class Iterator {
|
||||
Position m_pos;
|
||||
const DependencyTreeTracker* m_dtt;
|
||||
@@ -608,8 +619,21 @@ public:
|
||||
--m_current_depth;
|
||||
}
|
||||
|
||||
|
||||
Position common_ancestor_between(Position read_pos, Position write_pos)
|
||||
{
|
||||
// Early out when read and write are at the same position
|
||||
if (read_pos == write_pos)
|
||||
return read_pos;
|
||||
// Early out if either position is the root of the dependency tree
|
||||
if (read_pos == end_pos() || write_pos == end_pos())
|
||||
return end_pos();
|
||||
return search_for_common_ancestor_between(read_pos, write_pos);
|
||||
}
|
||||
|
||||
// Because this function makes use of stack arrays, ensure is NOT inlined
|
||||
// inside a loop to avoid repeatedly reserve stack space each iteration
|
||||
OSL_NOINLINE Position search_for_common_ancestor_between(Position read_pos,
|
||||
Position write_pos)
|
||||
{
|
||||
// To find common anscenstor
|
||||
// Walk up both paths building 2 stacks of positions
|
||||
@@ -619,8 +643,8 @@ public:
|
||||
auto write_iter = begin_at(write_pos);
|
||||
|
||||
const int read_count = read_iter.depth() + 1;
|
||||
OSL_STACK_ARRAY(Position, read_path, read_count);
|
||||
int read_depth = 0;
|
||||
Position* read_path = OSL_ALLOCA(Position, read_count);
|
||||
int read_depth = 0;
|
||||
{
|
||||
// Loop structure is to allow
|
||||
// writing the end position into the read path
|
||||
@@ -634,8 +658,8 @@ public:
|
||||
}
|
||||
|
||||
const int writeCount = write_iter.depth() + 1;
|
||||
OSL_STACK_ARRAY(Position, write_path, writeCount);
|
||||
int write_depth = 0;
|
||||
Position* write_path = OSL_ALLOCA(Position, writeCount);
|
||||
int write_depth = 0;
|
||||
{
|
||||
// Loop structure is to allow
|
||||
// writing the end position into the write path
|
||||
@@ -647,31 +671,53 @@ public:
|
||||
++write_iter;
|
||||
}
|
||||
}
|
||||
const int levelCount = std::min(read_depth, write_depth);
|
||||
const int read_level = read_depth - 1;
|
||||
const int write_level = write_depth - 1;
|
||||
OSL_ASSERT(write_path[write_level] == end_pos());
|
||||
OSL_ASSERT(read_path[read_level] == end_pos());
|
||||
|
||||
const int walkCount = std::min(read_depth, write_depth);
|
||||
const int read_top = read_depth - 1;
|
||||
const int write_top = write_depth - 1;
|
||||
OSL_DASSERT(write_top < writeCount);
|
||||
OSL_DASSERT(write_path[write_top] == end_pos());
|
||||
OSL_DASSERT(read_top < read_count);
|
||||
OSL_DASSERT(read_path[read_top] == end_pos());
|
||||
|
||||
int walkDepth = 0;
|
||||
// Verify top of read and write stacks match positions
|
||||
OSL_DASSERT((read_top - walkDepth) >= 0);
|
||||
OSL_DASSERT((read_top - walkDepth) < read_count);
|
||||
OSL_DASSERT((write_top - walkDepth) >= 0);
|
||||
OSL_DASSERT((write_top - walkDepth) < writeCount);
|
||||
OSL_DASSERT(read_path[read_top - walkDepth]
|
||||
== write_path[write_top - walkDepth]);
|
||||
// That position should technically be the root (no conditions in the dependency tree)
|
||||
OSL_DASSERT(read_path[read_top - walkDepth] == end_pos());
|
||||
// Because we know walkDepth 0 never differs, we can start iterating
|
||||
// at walkDepth 1
|
||||
|
||||
int level = 0;
|
||||
OSL_ASSERT(read_path[read_level - level]
|
||||
== write_path[write_level - level]);
|
||||
do {
|
||||
++level;
|
||||
if (read_path[read_level - level]()
|
||||
!= write_path[write_level - level]())
|
||||
// Walk down the read and write paths until they differ
|
||||
for (walkDepth = 1; walkDepth < walkCount; ++walkDepth) {
|
||||
OSL_DASSERT((read_top - walkDepth) >= 0);
|
||||
OSL_DASSERT((read_top - walkDepth) < read_count);
|
||||
OSL_DASSERT((write_top - walkDepth) >= 0);
|
||||
OSL_DASSERT((write_top - walkDepth) < writeCount);
|
||||
if (read_path[read_top - walkDepth]()
|
||||
!= write_path[write_top - walkDepth]()) {
|
||||
break;
|
||||
} while (level < levelCount);
|
||||
--level;
|
||||
OSL_ASSERT(read_path[read_level - level]
|
||||
== write_path[write_level - level]);
|
||||
OSL_ASSERT(read_level - level >= 0);
|
||||
return read_path[read_level - level];
|
||||
}
|
||||
}
|
||||
// The previous walk depth's position was the common ancestor
|
||||
--walkDepth;
|
||||
OSL_DASSERT((read_top - walkDepth) >= 0);
|
||||
OSL_DASSERT((read_top - walkDepth) < read_count);
|
||||
OSL_DASSERT((write_top - walkDepth) >= 0);
|
||||
OSL_DASSERT((write_top - walkDepth) < writeCount);
|
||||
OSL_DASSERT(read_path[read_top - walkDepth]
|
||||
== write_path[write_top - walkDepth]);
|
||||
return read_path[read_top - walkDepth];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Historically tracks stack of functions
|
||||
// The Position returned by top_pos changes and function scopes are pushed and popped.
|
||||
// However any given position is invariant as scopes change
|
||||
@@ -747,7 +793,6 @@ public:
|
||||
|
||||
FunctionTreeTracker(const FunctionTreeTracker&) = delete;
|
||||
|
||||
|
||||
class Iterator {
|
||||
Position m_pos;
|
||||
const FunctionTreeTracker* m_ftt;
|
||||
@@ -961,7 +1006,6 @@ public:
|
||||
m_nodes.push_back(node);
|
||||
}
|
||||
|
||||
|
||||
OSL_FORCEINLINE Position top_pos() const { return m_top_of_stack; }
|
||||
|
||||
OSL_FORCEINLINE void pop_function_call()
|
||||
@@ -995,6 +1039,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class WriteEvent {
|
||||
DependencyTreeTracker::Position m_pos_in_tree;
|
||||
int m_op_num;
|
||||
@@ -1034,18 +1080,22 @@ public:
|
||||
return m_op_num;
|
||||
}
|
||||
|
||||
|
||||
OSL_FORCEINLINE int loop_op_index() const { return m_loop_op_index; }
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<WriteEvent> WriteChronology;
|
||||
//typedef llvm::SmallVector<WriteEvent, 8> WriteChronology;
|
||||
|
||||
|
||||
|
||||
class ReadEvent {
|
||||
DependencyTreeTracker::Position m_pos_in_tree;
|
||||
#ifdef OSL_DEV
|
||||
int m_op_num;
|
||||
int m_loop_op_index;
|
||||
#endif
|
||||
|
||||
public:
|
||||
ReadEvent(DependencyTreeTracker::Position pos_in_tree_
|
||||
#ifdef OSL_DEV
|
||||
@@ -1067,16 +1117,25 @@ public:
|
||||
}
|
||||
|
||||
#ifdef OSL_DEV
|
||||
OSL_FORCEINLINE int op_num() const { return m_op_num; }
|
||||
OSL_FORCEINLINE int op_num() const
|
||||
{
|
||||
return m_op_num;
|
||||
}
|
||||
|
||||
OSL_FORCEINLINE int loop_op_index() const { return m_loop_op_index; }
|
||||
OSL_FORCEINLINE int loop_op_index() const
|
||||
{
|
||||
return m_loop_op_index;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<ReadEvent> ReadChronology;
|
||||
// Testing showed 6 read events a typically max
|
||||
//typedef llvm::SmallVector<ReadEvent, 6> ReadChronology;
|
||||
|
||||
|
||||
|
||||
class LoopStack {
|
||||
std::vector<int> m_conditions_op_index_stack;
|
||||
std::vector<const Symbol*> m_conditions_symbol_stack;
|
||||
@@ -1156,6 +1215,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct ReadBranch {
|
||||
DependencyTreeTracker::Position pos;
|
||||
int depth; // how deep in the m_conditional_symbol_stack did the read occur
|
||||
@@ -1167,6 +1228,8 @@ struct ReadBranch {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct Analyzer {
|
||||
BatchedAnalysis& m_ba;
|
||||
ShaderInstance* m_inst;
|
||||
@@ -1202,7 +1265,6 @@ struct Analyzer {
|
||||
|
||||
std::unordered_set<Symbol*> m_symbols_written_to_by_implicitly_varying_ops;
|
||||
|
||||
|
||||
// Remember which symbols we've force to be boolean so we can
|
||||
// reverse that decision if we see them used by any boolean operations
|
||||
std::unordered_set<Symbol*> m_symbols_logically_bool;
|
||||
@@ -1363,7 +1425,8 @@ struct Analyzer {
|
||||
op(write_op_num).requires_masking(true);
|
||||
OSL_DEV_ONLY(
|
||||
std::cout
|
||||
<< "cyclic read of " << symbol_to_check->unmangled().c_str()
|
||||
<< "cyclic read of "
|
||||
<< symbol_to_check->unmangled().c_str()
|
||||
<< " from loop [" << read_iter->loop_op_index()
|
||||
<< "] op(" << write_op_num << ").requires_masking()="
|
||||
<< op(write_op_num).requires_masking() << std::endl);
|
||||
@@ -1490,11 +1553,12 @@ struct Analyzer {
|
||||
for (auto cond_iter = m_conditional_symbol_stack.begin();
|
||||
*cond_iter != loop_condition; ++cond_iter) {
|
||||
auto conditionContinueDependsOn = *cond_iter;
|
||||
OSL_DEV_ONLY(std::cout << ">>>Loop Conditional "
|
||||
<< loop_condition->unmangled().c_str()
|
||||
<< " needs to depend on conditional "
|
||||
<< conditionContinueDependsOn->unmangled().c_str()
|
||||
<< std::endl);
|
||||
OSL_DEV_ONLY(std::cout
|
||||
<< ">>>Loop Conditional "
|
||||
<< loop_condition->unmangled().c_str()
|
||||
<< " needs to depend on conditional "
|
||||
<< conditionContinueDependsOn->unmangled().c_str()
|
||||
<< std::endl);
|
||||
m_symbols_dependent_upon.insert(
|
||||
std::make_pair(conditionContinueDependsOn, loop_condition));
|
||||
}
|
||||
@@ -1577,7 +1641,7 @@ struct Analyzer {
|
||||
// Process arguments written to to handle early outs, cyclical reads,
|
||||
// and record a WriteEvent to a potentially unmasked operations remembering
|
||||
// the exact stack of conditional dependencies at that point.
|
||||
// When we processed reads (above), we ensured that any reads occuring at a higher that on the stoCheck for
|
||||
// When we processed reads (above), we ensured that any reads occurring at a higher that on the stoCheck for
|
||||
for (int write_index = 0; write_index < write_count;
|
||||
++write_index) {
|
||||
const Symbol* symbolWrittenTo
|
||||
@@ -1624,7 +1688,7 @@ struct Analyzer {
|
||||
}
|
||||
}
|
||||
|
||||
// Special case for op_getattribute which normaly would be
|
||||
// Special case for op_getattribute which normally would be
|
||||
// implicitly varying unless BatchedRendererServices says it
|
||||
// is uniform.
|
||||
if (opcode.opname() == Strings::op_getattribute) {
|
||||
@@ -1718,7 +1782,6 @@ struct Analyzer {
|
||||
m_deferred_op_indices_to_be_masked.push_back(op_index);
|
||||
}
|
||||
|
||||
|
||||
// Track dependencies between symbols written to in this basic block
|
||||
// to the set of symbols the code blocks where dependent upon to be executed
|
||||
m_pos_in_dependent_sym_stack_by_op_index[op_index]
|
||||
@@ -1788,7 +1851,6 @@ struct Analyzer {
|
||||
OSL_ASSERT(read_count == 1);
|
||||
m_loop_stack.push_loop(op_index, symbols_read_by_op[0]);
|
||||
|
||||
|
||||
// Body block
|
||||
OSL_DEV_ONLY(std::cout << " FOR BODY BLOCK BEGIN"
|
||||
<< std::endl);
|
||||
@@ -1809,7 +1871,6 @@ struct Analyzer {
|
||||
OSL_ASSERT(m_conditional_symbol_stack.top() == condition);
|
||||
m_conditional_symbol_stack.pop();
|
||||
|
||||
|
||||
// Condition block
|
||||
// NOTE: Processing condition like it was a do/while
|
||||
// Although the first execution of the condition doesn't depend on the for loops conditions
|
||||
@@ -1837,7 +1898,6 @@ struct Analyzer {
|
||||
m_conditional_symbol_stack.pop();
|
||||
m_loop_stack.pop_loop(op_index);
|
||||
|
||||
|
||||
} else if (opcode.opname() == Strings::op_functioncall) {
|
||||
// Function call itself operates on the same symbol dependencies
|
||||
// as the current block, there was no conditionals involved
|
||||
@@ -2006,9 +2066,9 @@ struct Analyzer {
|
||||
continue;
|
||||
// Skip if it's an interpolated (userdata) parameter and we're
|
||||
// initializing them lazily.
|
||||
if ((s.symtype() == SymTypeParam || s.symtype() == SymTypeOutputParam)
|
||||
&& !s.lockgeom()
|
||||
&& !s.typespec().is_closure() && !s.connected()
|
||||
if ((s.symtype() == SymTypeParam
|
||||
|| s.symtype() == SymTypeOutputParam)
|
||||
&& !s.lockgeom() && !s.typespec().is_closure() && !s.connected()
|
||||
&& !s.connected_down() && m_ba.shadingsys().lazy_userdata())
|
||||
continue;
|
||||
// Set initial value for params (may contain init ops)
|
||||
@@ -2118,7 +2178,8 @@ struct Analyzer {
|
||||
OSL_DEV_ONLY(
|
||||
std::cout
|
||||
<< "Mapping "
|
||||
<< sym_mask_depends_on->unmangled().c_str()
|
||||
<< sym_mask_depends_on->unmangled()
|
||||
.c_str()
|
||||
<< std::endl);
|
||||
m_symbols_dependent_upon.insert(
|
||||
std::make_pair(sym_mask_depends_on,
|
||||
@@ -2140,7 +2201,7 @@ struct Analyzer {
|
||||
#endif
|
||||
const auto& early_out = *earlyOutIter;
|
||||
auto begin_dep_iter = m_conditional_symbol_stack.begin_at(
|
||||
early_out.dtt_pos);
|
||||
early_out.dtt_pos);
|
||||
auto end_dep_iter = m_conditional_symbol_stack.end();
|
||||
|
||||
const Opcode& opcode = m_opcodes[op_index];
|
||||
@@ -2166,7 +2227,8 @@ struct Analyzer {
|
||||
OSL_DEV_ONLY(
|
||||
std::cout
|
||||
<< "Mapping "
|
||||
<< sym_mask_depends_on->unmangled().c_str()
|
||||
<< sym_mask_depends_on->unmangled()
|
||||
.c_str()
|
||||
<< std::endl);
|
||||
m_symbols_dependent_upon.insert(
|
||||
std::make_pair(sym_mask_depends_on,
|
||||
@@ -2297,12 +2359,16 @@ struct Analyzer {
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
BatchedAnalysis::BatchedAnalysis(ShadingSystemImpl& shadingsys,
|
||||
ShaderGroup& group)
|
||||
: m_shadingsys(shadingsys), m_group(group)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedAnalysis::analyze_layer(ShaderInstance* inst)
|
||||
{
|
||||
@@ -2339,6 +2405,8 @@ BatchedAnalysis::analyze_layer(ShaderInstance* inst)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedAnalysis::dump_symbol_uniformity(ShaderInstance* inst)
|
||||
{
|
||||
@@ -2355,6 +2423,8 @@ BatchedAnalysis::dump_symbol_uniformity(ShaderInstance* inst)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedAnalysis::dump_layer(ShaderInstance* inst)
|
||||
{
|
||||
|
||||
@@ -45,11 +45,12 @@ static ustring fields[] = {
|
||||
ustring("objdata"), //
|
||||
ustring("shadingcontext"), //
|
||||
ustring("renderer"), //
|
||||
Strings::Ci, //
|
||||
Strings::raytype, //
|
||||
ustring("pad0"), //
|
||||
ustring("pad1"), //
|
||||
ustring("pad2"), //
|
||||
ustring("pad3"), //
|
||||
ustring("pad4"), //
|
||||
// Varying
|
||||
Strings::P, //
|
||||
ustring("dPdz"), //
|
||||
@@ -66,6 +67,7 @@ static ustring fields[] = {
|
||||
Strings::Ps, //
|
||||
Strings::object2common, //
|
||||
Strings::shader2common, //
|
||||
Strings::Ci, //
|
||||
Strings::surfacearea, //
|
||||
Strings::flipHandedness, //
|
||||
Strings::backfacing
|
||||
@@ -78,11 +80,12 @@ static bool field_is_uniform[] = {
|
||||
true, // objdata
|
||||
true, // shadingcontext
|
||||
true, // renderer
|
||||
true, // Ci
|
||||
true, // raytype
|
||||
true, // pad0
|
||||
true, // pad1
|
||||
true, // pad2
|
||||
true, // pad3
|
||||
true, // pad4
|
||||
// Varying
|
||||
false, // P
|
||||
false, // dPdz
|
||||
@@ -99,6 +102,7 @@ static bool field_is_uniform[] = {
|
||||
false, // Ps
|
||||
false, // object2common
|
||||
false, // shader2common
|
||||
false, // Ci,
|
||||
false, // surfacearea
|
||||
false, // flipHandedness
|
||||
false, // backfacing
|
||||
@@ -184,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_string();
|
||||
lt = (llvm::Type*)ll.type_ustring();
|
||||
else if (t.aggregate == TypeDesc::VEC3)
|
||||
lt = (llvm::Type*)ll.type_void_ptr(); //llvm_type_triple_ptr();
|
||||
else if (t.aggregate == TypeDesc::MATRIX44)
|
||||
@@ -205,6 +209,8 @@ BatchedBackendLLVM::llvm_pass_type(const TypeSpec& typespec)
|
||||
return lt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Type*
|
||||
BatchedBackendLLVM::llvm_pass_wide_type(const TypeSpec& typespec)
|
||||
{
|
||||
@@ -263,6 +269,11 @@ BatchedBackendLLVM::llvm_assign_zero(const Symbol& sym)
|
||||
zero = ll.constant(ustring());
|
||||
else
|
||||
zero = ll.wide_constant(ustring());
|
||||
} else if (elemtype.is_closure_based()) {
|
||||
if (sym.is_uniform())
|
||||
zero = ll.void_ptr_null();
|
||||
else
|
||||
zero = ll.widen_value(ll.void_ptr_null());
|
||||
} else {
|
||||
OSL_ASSERT(0 && "Unsupported element type");
|
||||
zero = nullptr;
|
||||
@@ -270,9 +281,8 @@ BatchedBackendLLVM::llvm_assign_zero(const Symbol& sym)
|
||||
|
||||
int num_elements = t.numelements();
|
||||
for (int a = 0; a < num_elements; ++a) {
|
||||
int numDeriv = sym.has_derivs() ? 3 : 1;
|
||||
llvm::Value* arrind = t.simpletype().arraylen ? ll.constant(a)
|
||||
: NULL;
|
||||
int numDeriv = sym.has_derivs() ? 3 : 1;
|
||||
llvm::Value* arrind = t.simpletype().arraylen ? ll.constant(a) : NULL;
|
||||
for (int d = 0; d < numDeriv; ++d) {
|
||||
for (int c = 0; c < t.aggregate(); ++c) {
|
||||
llvm_store_value(zero, sym, d, arrind, c);
|
||||
@@ -312,7 +322,6 @@ BatchedBackendLLVM::llvm_zero_derivs(const Symbol& sym)
|
||||
++arrayindex) {
|
||||
llvm::Value* arrind = arrayindex >= 0 ? ll.constant(arrayindex)
|
||||
: NULL;
|
||||
|
||||
for (int c = 0; c < t.aggregate(); ++c)
|
||||
llvm_store_value(zero, sym, 1, arrind, c);
|
||||
for (int c = 0; c < t.aggregate(); ++c)
|
||||
@@ -322,15 +331,15 @@ BatchedBackendLLVM::llvm_zero_derivs(const Symbol& sym)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedBackendLLVM::llvm_zero_derivs(const Symbol& sym, llvm::Value* count)
|
||||
{
|
||||
// Same thing as the above version but with just the first count derivs
|
||||
const TypeSpec& t = sym.typespec();
|
||||
|
||||
OSL_ASSERT((count->getType() == ll.type_int()) ||
|
||||
(count->getType() == ll.type_wide_int()));
|
||||
|
||||
OSL_ASSERT((count->getType() == ll.type_int())
|
||||
|| (count->getType() == ll.type_wide_int()));
|
||||
|
||||
if (t.is_closure_based())
|
||||
return; // Closures don't have derivs
|
||||
@@ -343,7 +352,7 @@ BatchedBackendLLVM::llvm_zero_derivs(const Symbol& sym, llvm::Value* count)
|
||||
else
|
||||
zero = ll.wide_constant(0.0f);
|
||||
|
||||
if(!t.is_array()) {
|
||||
if (!t.is_array()) {
|
||||
// Not an array, probably shouldn't have called this method
|
||||
// just fallback to non-count based version
|
||||
llvm_zero_derivs(sym);
|
||||
@@ -352,40 +361,45 @@ BatchedBackendLLVM::llvm_zero_derivs(const Symbol& sym, llvm::Value* count)
|
||||
|
||||
llvm::Value* pre_condition_mask = ll.current_mask();
|
||||
|
||||
llvm::Value * index_loc = ll.op_alloca(ll.type_int(), 1);
|
||||
llvm::Value* index_loc = ll.op_alloca(ll.type_int(), 1);
|
||||
ll.op_store(ll.constant(0), index_loc);
|
||||
|
||||
llvm::BasicBlock* cond_block = ll.new_basic_block ("zero deriv cond");
|
||||
llvm::BasicBlock* body_block = ll.new_basic_block ("zero deriv body");
|
||||
llvm::BasicBlock* step_block = ll.new_basic_block ("zero deriv step");
|
||||
llvm::BasicBlock* after_block = ll.new_basic_block ("zero deriv after");
|
||||
llvm::BasicBlock* cond_block = ll.new_basic_block("zero deriv cond");
|
||||
llvm::BasicBlock* body_block = ll.new_basic_block("zero deriv body");
|
||||
llvm::BasicBlock* step_block = ll.new_basic_block("zero deriv step");
|
||||
llvm::BasicBlock* after_block = ll.new_basic_block("zero deriv after");
|
||||
|
||||
ll.op_branch (cond_block);
|
||||
llvm::Value * index_val = ll.op_load(index_loc);
|
||||
llvm::Value * windex_val = ll.widen_value(index_val);
|
||||
llvm::Value * condition_mask = ll.op_lt(windex_val, count);
|
||||
llvm::Value * post_condition_mask = ll.op_and(condition_mask, pre_condition_mask);
|
||||
llvm::Value* cond_val = ll.test_if_mask_is_non_zero(post_condition_mask);
|
||||
ll.op_branch(cond_block);
|
||||
llvm::Value* index_val = ll.op_load(index_loc);
|
||||
llvm::Value* windex_val = ll.widen_value(index_val);
|
||||
llvm::Value* condition_mask = ll.op_lt(windex_val, count);
|
||||
llvm::Value* post_condition_mask = ll.op_and(condition_mask,
|
||||
pre_condition_mask);
|
||||
llvm::Value* cond_val = ll.test_if_mask_is_non_zero(
|
||||
post_condition_mask);
|
||||
|
||||
// Jump to either LoopBody or AfterLoop
|
||||
ll.op_branch (cond_val, body_block, after_block);
|
||||
ll.push_mask(post_condition_mask, false /* negate */, true /* absolute */);
|
||||
ll.op_branch(cond_val, body_block, after_block);
|
||||
ll.push_mask(post_condition_mask, false /* negate */,
|
||||
true /* absolute */);
|
||||
for (int c = 0; c < t.aggregate(); ++c)
|
||||
llvm_store_value(zero, sym, 1, index_val, c);
|
||||
for (int c = 0; c < t.aggregate(); ++c)
|
||||
llvm_store_value(zero, sym, 2, index_val, c);
|
||||
ll.pop_mask();
|
||||
|
||||
ll.op_branch (step_block);
|
||||
ll.op_branch(step_block);
|
||||
index_val = ll.op_add(index_val, ll.constant(1));
|
||||
ll.op_store(index_val, index_loc);
|
||||
ll.op_branch (cond_block);
|
||||
ll.op_branch(cond_block);
|
||||
|
||||
// Continue on with the previous flow
|
||||
ll.set_insert_point (after_block);
|
||||
ll.set_insert_point(after_block);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
BatchedBackendLLVM::ShaderGlobalNameToIndex(ustring name, bool& is_uniform)
|
||||
{
|
||||
@@ -399,6 +413,8 @@ BatchedBackendLLVM::ShaderGlobalNameToIndex(ustring name, bool& is_uniform)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::llvm_global_symbol_ptr(ustring name, bool& is_uniform)
|
||||
{
|
||||
@@ -410,6 +426,8 @@ BatchedBackendLLVM::llvm_global_symbol_ptr(ustring name, bool& is_uniform)
|
||||
return ll.void_ptr(ll.GEP(sg_ptr(), 0, sg_index));
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::getLLVMSymbolBase(const Symbol& sym)
|
||||
{
|
||||
@@ -441,14 +459,16 @@ BatchedBackendLLVM::getLLVMSymbolBase(const Symbol& sym)
|
||||
std::string mangled_name = dealiased->mangled();
|
||||
AllocationMap::iterator map_iter = named_values().find(mangled_name);
|
||||
if (map_iter == named_values().end()) {
|
||||
shadingcontext()->errorf(
|
||||
"Couldn't find symbol '%s' (unmangled = '%s'). Did you forget to allocate it?",
|
||||
mangled_name.c_str(), dealiased->unmangled());
|
||||
shadingcontext()->errorfmt(
|
||||
"Couldn't find symbol '{}' (unmangled = '{}'). Did you forget to allocate it?",
|
||||
mangled_name, dealiased->unmangled());
|
||||
return 0;
|
||||
}
|
||||
return (llvm::Value*)map_iter->second;
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::llvm_alloca(const TypeSpec& type, bool derivs,
|
||||
bool is_uniform, bool forceBool,
|
||||
@@ -476,12 +496,16 @@ BatchedBackendLLVM::llvm_alloca(const TypeSpec& type, bool derivs,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BatchedBackendLLVM::TempScope::TempScope(BatchedBackendLLVM& backend)
|
||||
: m_backend(backend)
|
||||
{
|
||||
m_backend.m_temp_scopes.push_back(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
BatchedBackendLLVM::TempScope::~TempScope()
|
||||
{
|
||||
OSL_ASSERT(!m_backend.m_temp_scopes.empty()
|
||||
@@ -497,6 +521,8 @@ BatchedBackendLLVM::TempScope::~TempScope()
|
||||
m_backend.m_temp_scopes.pop_back();
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::getOrAllocateTemp(const TypeSpec& type, bool derivs,
|
||||
bool is_uniform, bool forceBool,
|
||||
@@ -537,6 +563,8 @@ BatchedBackendLLVM::getOrAllocateTemp(const TypeSpec& type, bool derivs,
|
||||
return allocation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::getOrAllocateLLVMSymbol(const Symbol& sym)
|
||||
{
|
||||
@@ -620,6 +648,8 @@ BatchedBackendLLVM::llvm_get_pointer(const Symbol& sym, int deriv,
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::llvm_widen_value_into_temp(const Symbol& sym, int deriv)
|
||||
{
|
||||
@@ -633,7 +663,7 @@ BatchedBackendLLVM::llvm_widen_value_into_temp(const Symbol& sym, int deriv)
|
||||
OSL_ASSERT(symType.is_unknown() == false);
|
||||
|
||||
llvm::Value* widePtr = getOrAllocateTemp(t, false /*derivs*/,
|
||||
false /*is_uniform*/);
|
||||
false /*is_uniform*/);
|
||||
auto disable_masked_stores = ll.create_masking_scope(false);
|
||||
for (int c = 0; c < t.aggregate(); ++c) {
|
||||
// NOTE: we use the passed deriv to load, but store to value (deriv==0)
|
||||
@@ -644,6 +674,8 @@ BatchedBackendLLVM::llvm_widen_value_into_temp(const Symbol& sym, int deriv)
|
||||
return ll.void_ptr(widePtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::llvm_load_value(const Symbol& sym, int deriv,
|
||||
llvm::Value* arrayindex, int component,
|
||||
@@ -729,6 +761,7 @@ BatchedBackendLLVM::llvm_load_value(const Symbol& sym, int deriv,
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::llvm_load_mask(const Symbol& cond)
|
||||
{
|
||||
@@ -751,6 +784,7 @@ BatchedBackendLLVM::llvm_load_mask(const Symbol& cond)
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::llvm_load_value(llvm::Value* ptr, const TypeSpec& type,
|
||||
int deriv, llvm::Value* arrayindex,
|
||||
@@ -833,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) == (llvm::Type*)ll.type_string())
|
||||
|| (ll.llvm_typeof(result) == ll.type_ustring())
|
||||
|| (ll.llvm_typeof(result) == ll.type_matrix())
|
||||
|| (ll.llvm_typeof(result) == ll.type_longlong())) {
|
||||
result = ll.widen_value(result);
|
||||
@@ -854,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_string())
|
||||
|| (ll.llvm_typeof(result) == ll.type_wide_ustring())
|
||||
|| (ll.llvm_typeof(result) == ll.type_wide_bool())
|
||||
|| (ll.llvm_typeof(result) == ll.type_wide_matrix())
|
||||
|| (ll.llvm_typeof(result) == ll.type_wide_longlong()));
|
||||
@@ -888,7 +922,6 @@ BatchedBackendLLVM::llvm_load_value(llvm::Value* ptr, const TypeSpec& type,
|
||||
// vs. the hardcoded 4 and avoid the multiplication above
|
||||
}
|
||||
|
||||
|
||||
// Now grab the value
|
||||
llvm::Value* result;
|
||||
result = ll.op_gather(ptr, arrayindex);
|
||||
@@ -932,7 +965,6 @@ BatchedBackendLLVM::llvm_load_constant_value(const Symbol& sym, int arrayindex,
|
||||
OSL_ASSERT(arrayindex >= 0
|
||||
&& "Called llvm_load_constant_value with negative array index");
|
||||
|
||||
|
||||
// TODO: might want to take this fix for array types back to the non-wide backend
|
||||
TypeSpec elementType = sym.typespec();
|
||||
// The symbol we are creating a constant for might be an array
|
||||
@@ -971,7 +1003,7 @@ BatchedBackendLLVM::llvm_load_constant_value(const Symbol& sym, int arrayindex,
|
||||
}
|
||||
if (elementType.is_triple() || elementType.is_matrix()) {
|
||||
int ncomps = (int)sym.typespec().aggregate();
|
||||
float float_elem = sym.get_float(ncomps*arrayindex + component);
|
||||
float float_elem = sym.get_float(ncomps * arrayindex + component);
|
||||
if (op_is_uniform) {
|
||||
return ll.constant(float_elem);
|
||||
} else {
|
||||
@@ -1109,14 +1141,14 @@ BatchedBackendLLVM::llvm_load_arg(const Symbol& sym, bool derivs,
|
||||
int copy_deriv_count = (derivs && sym.has_derivs()) ? 3 : 1;
|
||||
|
||||
int copy_elem_count = t.numelements();
|
||||
bool is_array = t.is_array();
|
||||
bool is_array = t.is_array();
|
||||
for (int d = 0; d < copy_deriv_count; ++d) {
|
||||
for(int ai=0; ai < copy_elem_count; ++ai) {
|
||||
llvm::Value * arrayIndex = is_array ? ll.constant(ai) : nullptr;
|
||||
for (int ai = 0; ai < copy_elem_count; ++ai) {
|
||||
llvm::Value* arrayIndex = is_array ? ll.constant(ai) : nullptr;
|
||||
for (int c = 0; c < t.aggregate(); ++c) {
|
||||
|
||||
// Will automatically widen value if needed
|
||||
llvm::Value* v = llvm_load_value(sym, d, arrayIndex, c, TypeDesc::UNKNOWN,
|
||||
llvm::Value* v = llvm_load_value(sym, d, arrayIndex, c,
|
||||
TypeDesc::UNKNOWN,
|
||||
op_is_uniform);
|
||||
llvm_store_value(v, tmpptr, t, d, arrayIndex, c);
|
||||
}
|
||||
@@ -1186,7 +1218,8 @@ 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 (ll.type_ptr(ll.llvm_typeof(new_val)) != ll.llvm_typeof(dst_ptr)) {
|
||||
if ((const llvm::Type*)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);
|
||||
@@ -1199,10 +1232,9 @@ BatchedBackendLLVM::llvm_store_value(llvm::Value* new_val, llvm::Value* dst_ptr,
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
OSL_ASSERT(ll.type_ptr(ll.llvm_typeof(new_val))
|
||||
OSL_ASSERT((const llvm::Type*)ll.type_ptr(ll.llvm_typeof(new_val))
|
||||
== ll.llvm_typeof(dst_ptr));
|
||||
|
||||
|
||||
// Finally, store the value.
|
||||
ll.op_store(new_val, dst_ptr);
|
||||
return true;
|
||||
@@ -1245,6 +1277,7 @@ BatchedBackendLLVM::llvm_store_value(llvm::Value* new_val, llvm::Value* dst_ptr,
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
BatchedBackendLLVM::llvm_store_mask(llvm::Value* new_mask, const Symbol& cond)
|
||||
{
|
||||
@@ -1259,6 +1292,7 @@ BatchedBackendLLVM::llvm_store_mask(llvm::Value* new_mask, const Symbol& cond)
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
BatchedBackendLLVM::llvm_store_component_value(llvm::Value* new_val,
|
||||
const Symbol& sym, int deriv,
|
||||
@@ -1302,6 +1336,8 @@ BatchedBackendLLVM::llvm_store_component_value(llvm::Value* new_val,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedBackendLLVM::llvm_broadcast_uniform_value_from_mem(
|
||||
llvm::Value* pointerTotempUniform, const Symbol& Destination,
|
||||
@@ -1349,6 +1385,8 @@ BatchedBackendLLVM::llvm_broadcast_uniform_value_from_mem(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedBackendLLVM::llvm_broadcast_uniform_value(llvm::Value* tempUniform,
|
||||
const Symbol& Destination,
|
||||
@@ -1361,6 +1399,8 @@ BatchedBackendLLVM::llvm_broadcast_uniform_value(llvm::Value* tempUniform,
|
||||
llvm_store_value(wide_value, Destination, derivs, nullptr, component);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedBackendLLVM::llvm_conversion_store_masked_status(llvm::Value* val,
|
||||
const Symbol& Status)
|
||||
@@ -1383,6 +1423,8 @@ BatchedBackendLLVM::llvm_conversion_store_masked_status(llvm::Value* val,
|
||||
llvm_store_value(mask, Status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedBackendLLVM::llvm_conversion_store_uniform_status(llvm::Value* val,
|
||||
const Symbol& Status)
|
||||
@@ -1409,6 +1451,8 @@ BatchedBackendLLVM::llvm_conversion_store_uniform_status(llvm::Value* val,
|
||||
llvm_store_value(val, Status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::groupdata_field_ref(int fieldnum)
|
||||
{
|
||||
@@ -1416,6 +1460,7 @@ BatchedBackendLLVM::groupdata_field_ref(int fieldnum)
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::groupdata_field_ptr(int fieldnum, TypeDesc type,
|
||||
bool is_uniform)
|
||||
@@ -1431,6 +1476,8 @@ BatchedBackendLLVM::groupdata_field_ptr(int fieldnum, TypeDesc type,
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::temp_wide_matrix_ptr()
|
||||
{
|
||||
@@ -1444,6 +1491,7 @@ BatchedBackendLLVM::temp_wide_matrix_ptr()
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::temp_batched_texture_options_ptr()
|
||||
{
|
||||
@@ -1457,6 +1505,8 @@ BatchedBackendLLVM::temp_batched_texture_options_ptr()
|
||||
return m_llvm_temp_batched_texture_options_ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::temp_batched_trace_options_ptr()
|
||||
{
|
||||
@@ -1471,6 +1521,7 @@ BatchedBackendLLVM::temp_batched_trace_options_ptr()
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value*
|
||||
BatchedBackendLLVM::layer_run_ref(int layer)
|
||||
{
|
||||
@@ -1615,7 +1666,6 @@ BatchedBackendLLVM::llvm_call_function(const FuncSpec& name,
|
||||
valargs[i] = ll.void_ptr(tmpptr);
|
||||
}
|
||||
|
||||
|
||||
OSL_DEV_ONLY(std::cout << "....pushing " << s.name().c_str()
|
||||
<< " as void_ptr" << std::endl);
|
||||
} else {
|
||||
@@ -1717,7 +1767,8 @@ 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) == ll.type_ptr(ll.type_bool())) {
|
||||
if (ll.llvm_typeof(llvmValue)
|
||||
== (const llvm::Type*)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));
|
||||
@@ -1763,14 +1814,16 @@ BatchedBackendLLVM::llvm_assign_impl(const Symbol& Result, const Symbol& Src,
|
||||
llvm::Value* arrind = arrayindex >= 0 ? ll.constant(arrayindex) : NULL;
|
||||
|
||||
if (Result.typespec().is_closure() || Src.typespec().is_closure()) {
|
||||
OSL_ASSERT(0 && "unhandled case"); // TODO: implement
|
||||
|
||||
if (Src.typespec().is_closure()) {
|
||||
llvm::Value* srcval = llvm_load_value(Src, 0, arrind, 0);
|
||||
llvm::Value* srcval = llvm_load_value(Src, 0, arrind, 0,
|
||||
TypeDesc::UNKNOWN,
|
||||
op_is_uniform);
|
||||
llvm_store_value(srcval, Result, 0, arrind, 0);
|
||||
} else {
|
||||
llvm::Value* null = ll.constant_ptr(NULL, ll.type_void_ptr());
|
||||
llvm_store_value(null, Result, 0, arrind, 0);
|
||||
llvm::Value* null_value = ll.constant_ptr(NULL, ll.type_void_ptr());
|
||||
if (!op_is_uniform)
|
||||
null_value = ll.widen_value(null_value);
|
||||
llvm_store_value(null_value, Result, 0, arrind, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1795,7 +1848,7 @@ BatchedBackendLLVM::llvm_assign_impl(const Symbol& Result, const Symbol& Src,
|
||||
return true;
|
||||
}
|
||||
|
||||
// memcpy complicated by promotion of uniform to wide during assignment, dissallow
|
||||
// memcpy complicated by promotion of uniform to wide during assignment, disallow
|
||||
|
||||
// The following code handles f=f, f=i, v=v, v=f, v=i, m=m, s=s.
|
||||
// Remember that llvm_load_value will automatically convert scalar->triple.
|
||||
@@ -1812,7 +1865,7 @@ BatchedBackendLLVM::llvm_assign_impl(const Symbol& Result, const Symbol& Src,
|
||||
if (result_t.is_array() && src_t.is_array()) {
|
||||
start_array_index = 0;
|
||||
end_array_index = std::min(result_t.arraylength(),
|
||||
src_t.arraylength());
|
||||
src_t.arraylength());
|
||||
}
|
||||
}
|
||||
for (arrayindex = start_array_index; arrayindex < end_array_index;
|
||||
@@ -1853,7 +1906,7 @@ BatchedBackendLLVM::llvm_assign_impl(const Symbol& Result, const Symbol& Src,
|
||||
// The llvm_load_value above should have handled bool to int conversions
|
||||
// when the basetype == Typedesc::INT
|
||||
|
||||
// write source float into all compnents when dstcomp == -1, otherwise
|
||||
// write source float into all components when dstcomp == -1, otherwise
|
||||
// the single element requested.
|
||||
if (dstcomp == -1) {
|
||||
for (int i = 0; i < num_components; ++i)
|
||||
@@ -1905,6 +1958,8 @@ BatchedBackendLLVM::llvm_assign_impl(const Symbol& Result, const Symbol& Src,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
BatchedBackendLLVM::find_userdata_index(const Symbol& sym)
|
||||
{
|
||||
@@ -1921,6 +1976,7 @@ BatchedBackendLLVM::find_userdata_index(const Symbol& sym)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedBackendLLVM::append_arg_to(llvm::raw_svector_ostream& OS,
|
||||
const FuncSpec::Arg& arg)
|
||||
@@ -1949,6 +2005,8 @@ BatchedBackendLLVM::append_arg_to(llvm::raw_svector_ostream& OS,
|
||||
OS << name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char*
|
||||
BatchedBackendLLVM::build_name(const FuncSpec& fs)
|
||||
{
|
||||
|
||||
@@ -164,7 +164,7 @@ public:
|
||||
llvm::Value* llvm_load_mask(const Symbol& cond);
|
||||
|
||||
/// Return an llvm::Value* that is either a scalar and derivs is
|
||||
/// false, or a pointer to sym's values (if sym is an aggreate or
|
||||
/// 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,
|
||||
@@ -278,9 +278,9 @@ public:
|
||||
|
||||
public:
|
||||
TempScope(BatchedBackendLLVM& backend);
|
||||
TempScope(const TempScope& other) = delete;
|
||||
TempScope(const TempScope&& other) = delete;
|
||||
TempScope& operator=(const TempScope& other) = delete;
|
||||
TempScope(const TempScope& other) = delete;
|
||||
TempScope(const TempScope&& other) = delete;
|
||||
TempScope& operator=(const TempScope& other) = delete;
|
||||
TempScope& operator=(const TempScope&& other) = delete;
|
||||
~TempScope();
|
||||
};
|
||||
@@ -331,7 +331,7 @@ public:
|
||||
/// derivs are zero.
|
||||
llvm::Value* llvm_test_nonzero(const Symbol& val, bool test_derivs = false);
|
||||
|
||||
/// Implementaiton of Simple assignment. If arrayindex >= 0, in
|
||||
/// Implementation of Simple assignment. If arrayindex >= 0, in
|
||||
/// designates a particular array index to assign.
|
||||
bool llvm_assign_impl(const Symbol& Result, const Symbol& Src,
|
||||
int arrayindex = -1, int srccomp = -1,
|
||||
@@ -364,6 +364,7 @@ public:
|
||||
|
||||
llvm::Type* llvm_type_closure_component();
|
||||
llvm::Type* llvm_type_closure_component_ptr();
|
||||
llvm::Type* llvm_type_closure_component_wide_ptr();
|
||||
|
||||
/// Return the ShaderGlobals pointer cast as a void*.
|
||||
///
|
||||
@@ -415,13 +416,16 @@ public:
|
||||
|
||||
|
||||
/// Return the pointer to the block of shadeindices.
|
||||
llvm::Value *wide_shadeindex_ptr () const { return m_llvm_wide_shadeindex_ptr; }
|
||||
llvm::Value* wide_shadeindex_ptr() const
|
||||
{
|
||||
return m_llvm_wide_shadeindex_ptr;
|
||||
}
|
||||
|
||||
/// Return the userdata base pointer.
|
||||
llvm::Value *userdata_base_ptr () const { return m_llvm_userdata_base_ptr; }
|
||||
llvm::Value* userdata_base_ptr() const { return m_llvm_userdata_base_ptr; }
|
||||
|
||||
/// Return the output base pointer.
|
||||
llvm::Value *output_base_ptr () const { return m_llvm_output_base_ptr; }
|
||||
llvm::Value* output_base_ptr() const { return m_llvm_output_base_ptr; }
|
||||
|
||||
/// Return a pointer to an WideMatrix that was previously alloca
|
||||
/// on the stack, meant for generator to reuse as a temporary
|
||||
@@ -485,7 +489,7 @@ public:
|
||||
|
||||
// Encapsulate creation of function names that encode parameter types,
|
||||
// including if each is varying or uniform, and if a mask is required.
|
||||
// Utilize llvm::Twine to efficently combine multiple strings
|
||||
// Utilize llvm::Twine to efficiently combine multiple strings
|
||||
// Usage is to start with the function name then append arguments,
|
||||
// and at any point masking can be turned on/off as well as batching.
|
||||
// The effect of disabling batching would be the function name is
|
||||
@@ -529,7 +533,7 @@ public:
|
||||
ArgVector m_args;
|
||||
|
||||
public:
|
||||
FuncSpec(const FuncSpec&) = delete;
|
||||
FuncSpec(const FuncSpec&) = delete;
|
||||
FuncSpec& operator=(const FuncSpec&) = delete;
|
||||
|
||||
FuncSpec(const llvm::Twine& name)
|
||||
@@ -677,9 +681,8 @@ public:
|
||||
llvm::BasicBlock* llvm_exit_instance_block()
|
||||
{
|
||||
if (!m_exit_instance_block) {
|
||||
std::string name = Strutil::sprintf("%s_%d_exit_",
|
||||
inst()->layername(),
|
||||
inst()->id());
|
||||
std::string name = fmtformat("{}_{}_exit_", inst()->layername(),
|
||||
inst()->id());
|
||||
m_exit_instance_block = ll.new_basic_block(name);
|
||||
}
|
||||
return m_exit_instance_block;
|
||||
@@ -750,12 +753,11 @@ private:
|
||||
virtual const char* library_selector() const = 0;
|
||||
virtual void init_function_map(ShadingSystemImpl& shadingsys) const = 0;
|
||||
|
||||
static std::unique_ptr<TargetLibraryHelper> build(ShadingContext* context,
|
||||
int vector_width,
|
||||
TargetISA target_isa);
|
||||
static std::unique_ptr<TargetLibraryHelper>
|
||||
build(ShadingContext* context, int vector_width, TargetISA target_isa);
|
||||
};
|
||||
// TargetLibraryHelper is private, so need to be friend with Concrete
|
||||
template <int WidthT, TargetISA IsaT>
|
||||
template<int WidthT, TargetISA IsaT>
|
||||
friend class ConcreteTargetLibraryHelper;
|
||||
|
||||
std::unique_ptr<TargetLibraryHelper> m_target_lib_helper;
|
||||
@@ -780,9 +782,9 @@ private:
|
||||
llvm::Value* m_llvm_shaderglobals_ptr;
|
||||
llvm::Value* m_llvm_groupdata_ptr;
|
||||
|
||||
llvm::Value *m_llvm_wide_shadeindex_ptr;
|
||||
llvm::Value *m_llvm_userdata_base_ptr;
|
||||
llvm::Value *m_llvm_output_base_ptr;
|
||||
llvm::Value* m_llvm_wide_shadeindex_ptr;
|
||||
llvm::Value* m_llvm_userdata_base_ptr;
|
||||
llvm::Value* m_llvm_output_base_ptr;
|
||||
|
||||
// Reused allocas for temps used to pass options or intermediates
|
||||
llvm::Value* m_llvm_temp_wide_matrix_ptr; // for gen_tranform
|
||||
|
||||
+3981
-3090
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,7 @@
|
||||
#include "batched_backendllvm.h"
|
||||
#include "oslexec_pvt.h"
|
||||
|
||||
// Create extrenal declarations for all built-in funcs we may call from LLVM
|
||||
// Create external declarations for all built-in funcs we may call from LLVM
|
||||
#define DECL(name, signature) extern "C" void name();
|
||||
#include "builtindecl.h"
|
||||
#undef DECL
|
||||
@@ -142,6 +142,8 @@ possibly_wide_type_from_code(const char* code, int* advance, bool& is_uniform)
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct HelperFuncRecord {
|
||||
const char* argtypes;
|
||||
void (*function)();
|
||||
@@ -168,6 +170,8 @@ struct HelperFuncRecord {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// As we will be using compile time const char * to populate the HelperFuncMap
|
||||
// We avoid std::string (which would create a copy), and instead just store
|
||||
// the const char *, however we must supply our own hashing and equality
|
||||
@@ -188,6 +192,8 @@ struct CStrHash {
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CStrEquality {
|
||||
OSL_FORCEINLINE bool operator()(const char* lhs, const char* rhs) const
|
||||
{
|
||||
@@ -195,12 +201,15 @@ struct CStrEquality {
|
||||
return is_equal;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef std::unordered_map<const char*, HelperFuncRecord, CStrHash, CStrEquality>
|
||||
HelperFuncMap;
|
||||
static HelperFuncMap llvm_helper_function_map;
|
||||
static atomic_int llvm_helper_function_map_initialized(0);
|
||||
static spin_mutex llvm_helper_function_map_mutex;
|
||||
|
||||
|
||||
static void
|
||||
initialize_llvm_helper_function_map()
|
||||
{
|
||||
@@ -217,11 +226,14 @@ initialize_llvm_helper_function_map()
|
||||
llvm_helper_function_map_initialized = 1;
|
||||
}
|
||||
|
||||
|
||||
struct NameAndSignature {
|
||||
const char* name;
|
||||
const char* signature;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// As we don't now the sizeof ConcreteT::library_functions until specialization,
|
||||
// we need a helper template function to defer its resolution
|
||||
template<typename ConcreteT>
|
||||
@@ -254,7 +266,6 @@ init_wide_function_map(const ConcreteT&, ShadingSystemImpl& shadingsys)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
auto shared_lib = OIIO::Plugin::open(filename, /*global=*/false);
|
||||
if (shared_lib == 0) {
|
||||
shadingsys.errorfmt("{} could not be loaded with error \"{}\"",
|
||||
@@ -287,6 +298,8 @@ init_wide_function_map(const ConcreteT&, ShadingSystemImpl& shadingsys)
|
||||
is_initialized = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT, TargetISA IsaT>
|
||||
class ConcreteTargetLibraryHelper final
|
||||
: public BatchedBackendLLVM::TargetLibraryHelper {
|
||||
@@ -312,6 +325,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Specialize ConcreteTargetLibraryHelper<>::library_functions and
|
||||
// ConcreteTargetLibraryHelper<>::library_selector_string for each
|
||||
// WidthT and TargetISA that we are building a shared library for.
|
||||
@@ -511,6 +526,8 @@ const char*
|
||||
= "b8_AVX_";
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
std::unique_ptr<BatchedBackendLLVM::TargetLibraryHelper>
|
||||
BatchedBackendLLVM::TargetLibraryHelper::build(ShadingContext* context,
|
||||
int vector_width,
|
||||
@@ -531,8 +548,7 @@ BatchedBackendLLVM::TargetLibraryHelper::build(ShadingContext* context,
|
||||
return RetType(
|
||||
new ConcreteTargetLibraryHelper<16, TargetISA::AVX512_noFMA>());
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
@@ -562,18 +578,20 @@ BatchedBackendLLVM::TargetLibraryHelper::build(ShadingContext* context,
|
||||
return RetType(
|
||||
new ConcreteTargetLibraryHelper<8, TargetISA::AVX>());
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
default: OSL_ASSERT(0 && "unsupported vector width");
|
||||
}
|
||||
std::cerr << "Build is not configured to support TargetISA of " <<
|
||||
LLVM_Util::target_isa_name(target_isa) << " and batch_size of " << vector_width << std::endl << std::flush;
|
||||
std::cerr << "Build is not configured to support TargetISA of "
|
||||
<< LLVM_Util::target_isa_name(target_isa) << " and batch_size of "
|
||||
<< vector_width << std::endl
|
||||
<< std::flush;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void*
|
||||
helper_function_lookup(const std::string& name)
|
||||
{
|
||||
@@ -619,12 +637,12 @@ BatchedBackendLLVM::llvm_type_sg()
|
||||
sg_types.push_back(vp); // opaque objdata*
|
||||
sg_types.push_back(vp); // ShadingContext*
|
||||
sg_types.push_back(vp); // RendererServices*
|
||||
sg_types.push_back(vp); // Ci
|
||||
sg_types.push_back(ll.type_int()); // raytype
|
||||
sg_types.push_back(ll.type_int()); // pad0
|
||||
sg_types.push_back(ll.type_int()); // pad1
|
||||
sg_types.push_back(ll.type_int()); // pad2
|
||||
|
||||
sg_types.push_back(ll.type_int()); // pad3
|
||||
sg_types.push_back(ll.type_int()); // pad4
|
||||
|
||||
// VaryingShaderGlobals of the batch
|
||||
sg_types.push_back(wide_triple_deriv); // P, dPdx, dPdy
|
||||
@@ -644,6 +662,8 @@ BatchedBackendLLVM::llvm_type_sg()
|
||||
sg_types.push_back(wide_vp); // object2common
|
||||
sg_types.push_back(wide_vp); // shader2common
|
||||
|
||||
sg_types.push_back(wide_vp); // Ci
|
||||
|
||||
sg_types.push_back(ll.type_wide_float()); // surfacearea
|
||||
sg_types.push_back(ll.type_wide_int()); // flipHandedness
|
||||
sg_types.push_back(ll.type_wide_int()); // backfacing
|
||||
@@ -653,6 +673,7 @@ BatchedBackendLLVM::llvm_type_sg()
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Type*
|
||||
BatchedBackendLLVM::llvm_type_batched_texture_options()
|
||||
{
|
||||
@@ -697,7 +718,6 @@ BatchedBackendLLVM::llvm_type_batched_texture_options()
|
||||
= ll.type_struct(sg_types, "BatchedTextureOptions",
|
||||
false /*is_packed*/);
|
||||
|
||||
|
||||
#if 0 && defined(OSL_DEV)
|
||||
std::cout << std::endl << std::endl << "llvm's data layout of BatchedTextureOptions" << std::endl;
|
||||
ll.dump_struct_data_layout(llvm_type_batched_texture_options());
|
||||
@@ -728,6 +748,7 @@ BatchedBackendLLVM::llvm_type_batched_texture_options()
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Type*
|
||||
BatchedBackendLLVM::llvm_type_batched_trace_options()
|
||||
{
|
||||
@@ -739,11 +760,10 @@ 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(
|
||||
reinterpret_cast<llvm::Type*>(ll.type_string())); // 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(ll.type_ustring()); // traceset
|
||||
|
||||
m_llvm_type_batched_trace_options = ll.type_struct(sg_types, "TraceOptions",
|
||||
false /*is_packed*/);
|
||||
@@ -773,6 +793,7 @@ BatchedBackendLLVM::llvm_type_batched_trace_options()
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Type*
|
||||
BatchedBackendLLVM::llvm_type_sg_ptr()
|
||||
{
|
||||
@@ -872,11 +893,11 @@ BatchedBackendLLVM::llvm_type_groupdata()
|
||||
fields.push_back(llvm_wide_type(ts));
|
||||
|
||||
// Alignment
|
||||
// TODO: this isn't quite right, cant rely on batch size to == ISA SIMD requirements
|
||||
size_t align = sym.typespec().is_closure_based()
|
||||
? sizeof(void*)
|
||||
: sym.typespec().simpletype().basesize()
|
||||
* m_width;
|
||||
// TODO: this isn't quite right, can't rely on batch size to == ISA SIMD requirements
|
||||
size_t base_size = sym.typespec().is_closure_based()
|
||||
? sizeof(void*)
|
||||
: sym.typespec().simpletype().basesize();
|
||||
size_t align = base_size * m_width;
|
||||
if (offset & (align - 1))
|
||||
offset += align - (offset & (align - 1));
|
||||
if (llvm_debug() >= 2)
|
||||
@@ -894,14 +915,13 @@ BatchedBackendLLVM::llvm_type_groupdata()
|
||||
}
|
||||
group().llvm_groupdata_wide_size(offset);
|
||||
if (llvm_debug() >= 2)
|
||||
std::cout << " Group struct had " << order << " fields, total size "
|
||||
<< offset << "\n\n";
|
||||
OSL::print(" Group struct had {} fields, total size {}\n\n", order,
|
||||
offset);
|
||||
|
||||
std::string groupdataname
|
||||
= Strutil::sprintf("Groupdata_%llu",
|
||||
(long long unsigned int)group().name().hash());
|
||||
m_llvm_type_groupdata = ll.type_struct(fields, groupdataname,
|
||||
false /*is_packed*/);
|
||||
std::string groupdataname = fmtformat("Groupdata_{}",
|
||||
group().name().hash());
|
||||
m_llvm_type_groupdata = ll.type_struct(fields, groupdataname,
|
||||
false /*is_packed*/);
|
||||
|
||||
return m_llvm_type_groupdata;
|
||||
}
|
||||
@@ -940,6 +960,13 @@ BatchedBackendLLVM::llvm_type_closure_component_ptr()
|
||||
}
|
||||
|
||||
|
||||
llvm::Type*
|
||||
BatchedBackendLLVM::llvm_type_closure_component_wide_ptr()
|
||||
{
|
||||
return ll.type_wide(llvm_type_closure_component_ptr());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedBackendLLVM::llvm_assign_initial_value(
|
||||
@@ -965,7 +992,7 @@ BatchedBackendLLVM::llvm_assign_initial_value(
|
||||
return;
|
||||
}
|
||||
|
||||
bool isarray = sym.typespec().is_array();
|
||||
bool isarray = sym.typespec().is_array();
|
||||
if ((sym.symtype() == SymTypeLocal || sym.symtype() == SymTypeTemp)
|
||||
&& shadingsys().debug_uninit()) {
|
||||
// Handle the "debug uninitialized values" case
|
||||
@@ -1030,7 +1057,7 @@ BatchedBackendLLVM::llvm_assign_initial_value(
|
||||
// generating the get_userdata callback?
|
||||
llvm::BasicBlock* after_userdata_block = nullptr;
|
||||
bool partial_userdata_mask_was_pushed = false;
|
||||
const SymLocationDesc* symloc = nullptr;
|
||||
const SymLocationDesc* symloc = nullptr;
|
||||
LLVM_Util::ScopedMasking partial_data_masking_scope;
|
||||
if (!sym.lockgeom() && !sym.typespec().is_closure()) {
|
||||
ustring symname = sym.name();
|
||||
@@ -1045,57 +1072,66 @@ BatchedBackendLLVM::llvm_assign_initial_value(
|
||||
llvm::Value* got_userdata = nullptr;
|
||||
// See if userdata input placement has been used for this symbol
|
||||
ustring layersym = ustring::fmtformat("{}.{}", inst()->layername(),
|
||||
sym.name());
|
||||
symloc = group().find_symloc(layersym, SymArena::UserData);
|
||||
if (! symloc)
|
||||
sym.name());
|
||||
symloc = group().find_symloc(layersym, SymArena::UserData);
|
||||
if (!symloc)
|
||||
symloc = group().find_symloc(sym.name(), SymArena::UserData);
|
||||
if (symloc) {
|
||||
// We had a userdata pre-placement record for this variable.
|
||||
// Just copy from the correct offset location!
|
||||
|
||||
// Strutil::print("GEN found placeable userdata input {} -> {} {} size={}\n",
|
||||
// sym.name(), symloc->name, sym.typespec(),
|
||||
// symloc->type.size());
|
||||
const int deriv_count = (symloc->derivs && sym.has_derivs()) ? 3 : 1;
|
||||
// OSL::print("GEN found placeable userdata input {} -> {} {} size={}\n",
|
||||
// sym.name(), symloc->name, sym.typespec(),
|
||||
// symloc->type.size());
|
||||
const int deriv_count = (symloc->derivs && sym.has_derivs()) ? 3
|
||||
: 1;
|
||||
|
||||
llvm::Value* sym_offset = ll.constanti64(symloc->offset);
|
||||
llvm::Value* userdata_sym_base_ptr = ll.ptr_cast(ll.offset_ptr(m_llvm_userdata_base_ptr, sym_offset), type.scalartype());
|
||||
llvm::Value* userdata_sym_base_ptr
|
||||
= ll.ptr_cast(ll.offset_ptr(m_llvm_userdata_base_ptr,
|
||||
sym_offset),
|
||||
type.scalartype());
|
||||
bool isBase32bit = (symloc->type != TypeDesc::STRING);
|
||||
int bytesPerElem = isBase32bit ? 4 : 8;
|
||||
// TODO: could move assert inside SymLocation
|
||||
OSL_ASSERT((symloc->stride % bytesPerElem) == 0);
|
||||
|
||||
llvm::Value* wide_shadeindex = ll.op_load(ll.type_wide_int(), m_llvm_wide_shadeindex_ptr);
|
||||
const int elem_stride = static_cast<int>(symloc->stride/bytesPerElem);
|
||||
llvm::Value* wide_shadeindex
|
||||
= ll.op_load(ll.type_wide_int(), m_llvm_wide_shadeindex_ptr);
|
||||
const int elem_stride = static_cast<int>(symloc->stride
|
||||
/ bytesPerElem);
|
||||
llvm::Value* wide_index_for_userdata = nullptr;
|
||||
if (elem_stride == 1) {
|
||||
wide_index_for_userdata = wide_shadeindex;
|
||||
} else {
|
||||
llvm::Value* element_stride = ll.wide_constant(elem_stride);
|
||||
wide_index_for_userdata = ll.op_mul(element_stride, wide_shadeindex);
|
||||
wide_index_for_userdata = ll.op_mul(element_stride,
|
||||
wide_shadeindex);
|
||||
}
|
||||
|
||||
const int elem_count = static_cast<int>(type.numelements());
|
||||
const int comp_count = type.aggregate;
|
||||
const int elem_count = static_cast<int>(type.numelements());
|
||||
const int comp_count = type.aggregate;
|
||||
|
||||
int c = 0;
|
||||
for (int d = 0; d < deriv_count; ++d) {
|
||||
for (int a = 0; a < elem_count; ++a) {
|
||||
llvm::Value* arrind = isarray ? ll.constant(a)
|
||||
: nullptr;
|
||||
llvm::Value* arrind = isarray ? ll.constant(a) : nullptr;
|
||||
for (int i = 0; i < comp_count; ++i, ++c) {
|
||||
llvm::Value* wide_index = wide_index_for_userdata;
|
||||
if (c != 0) {
|
||||
wide_index = ll.op_add(wide_index_for_userdata, ll.wide_constant(c));
|
||||
wide_index = ll.op_add(wide_index_for_userdata,
|
||||
ll.wide_constant(c));
|
||||
}
|
||||
// For ISA without a native mask (AVX & AVX2), this gather op will
|
||||
// clamp the indices of masked off lanes to 0.
|
||||
// This means the user data base pointer + sym_offset
|
||||
// must be dereferencable with a shadeindex of 0.
|
||||
llvm::Value *wide_val = ll.op_gather(userdata_sym_base_ptr, wide_index);
|
||||
// must be dereferenceable with a shadeindex of 0.
|
||||
llvm::Value* wide_val
|
||||
= ll.op_gather(userdata_sym_base_ptr, wide_index);
|
||||
|
||||
llvm_store_value(wide_val, sym, d, arrind,
|
||||
/*component*/i, /*index_is_uniform*/true);
|
||||
/*component*/ i,
|
||||
/*index_is_uniform*/ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1148,11 +1184,12 @@ BatchedBackendLLVM::llvm_assign_initial_value(
|
||||
// happen if the userdata was retrieved.
|
||||
llvm::BasicBlock* partial_userdata_block = ll.new_basic_block(
|
||||
"partial_userdata");
|
||||
after_userdata_block = ll.new_basic_block();
|
||||
after_userdata_block = ll.new_basic_block();
|
||||
OSL_ASSERT(got_userdata != nullptr);
|
||||
llvm::Value* cond_val = ll.op_ne(got_userdata,
|
||||
llvm_initial_shader_mask_value);
|
||||
ll.op_branch(cond_val, partial_userdata_block, after_userdata_block);
|
||||
ll.op_branch(cond_val, partial_userdata_block,
|
||||
after_userdata_block);
|
||||
|
||||
// If we got no or partial user data, we need to mask out the lanes
|
||||
// that successfully got user data from the initops or default value
|
||||
@@ -1161,7 +1198,8 @@ BatchedBackendLLVM::llvm_assign_initial_value(
|
||||
ll.push_mask(
|
||||
got_userdata_mask, /* negate */
|
||||
true /*, absolute = false (not sure how it wouldn't be an absolute mask) */);
|
||||
partial_data_masking_scope = ll.create_masking_scope(/*enabled=*/true);
|
||||
partial_data_masking_scope = ll.create_masking_scope(
|
||||
/*enabled=*/true);
|
||||
partial_userdata_mask_was_pushed = true;
|
||||
}
|
||||
}
|
||||
@@ -1203,25 +1241,28 @@ BatchedBackendLLVM::llvm_assign_initial_value(
|
||||
continue;
|
||||
for (int i = 0; i < num_components; ++i, ++c) {
|
||||
llvm::Value* init_val = nullptr;
|
||||
if(! sym.lockgeom() && ! sym.typespec().is_closure()) {
|
||||
if (!sym.lockgeom() && !sym.typespec().is_closure()) {
|
||||
// Reload value from symbol memory as reparam
|
||||
// may have changed it
|
||||
llvm::PointerType * ptr_type = nullptr;
|
||||
llvm::Type * data_type = nullptr;
|
||||
llvm::PointerType* ptr_type = nullptr;
|
||||
llvm::Type* data_type = nullptr;
|
||||
if (elemtype.is_float_based()) {
|
||||
ptr_type = ll.type_float_ptr();
|
||||
ptr_type = ll.type_float_ptr();
|
||||
data_type = ll.type_float();
|
||||
} else if (elemtype.is_string()) {
|
||||
ptr_type = ll.type_ustring_ptr();
|
||||
data_type = static_cast<llvm::Type *>(ll.type_string());
|
||||
ptr_type = ll.type_ustring_ptr();
|
||||
data_type = ll.type_ustring();
|
||||
} else if (elemtype.is_int()) {
|
||||
ptr_type = ll.type_int_ptr();
|
||||
ptr_type = ll.type_int_ptr();
|
||||
data_type = ll.type_int();
|
||||
}
|
||||
OSL_ASSERT(ptr_type && data_type);
|
||||
|
||||
llvm::Value * sym_data_src = ll.GEP(data_type, ll.constant_ptr (sym.dataptr(), ptr_type), c);
|
||||
init_val = ll.op_load (data_type, sym_data_src);
|
||||
llvm::Value* sym_data_src
|
||||
= ll.GEP(data_type,
|
||||
ll.constant_ptr(sym.dataptr(), ptr_type),
|
||||
c);
|
||||
init_val = ll.op_load(data_type, sym_data_src);
|
||||
OSL_ASSERT(init_val);
|
||||
if (sym.is_varying()) {
|
||||
init_val = ll.widen_value(init_val);
|
||||
@@ -1263,8 +1304,7 @@ BatchedBackendLLVM::llvm_assign_initial_value(
|
||||
// next basic block now.
|
||||
ll.op_branch(after_userdata_block);
|
||||
// NOTE: we must be in the after block to apply the exit mask
|
||||
if (ll.masked_exit_count() > exit_count_before_init_ops)
|
||||
{
|
||||
if (ll.masked_exit_count() > exit_count_before_init_ops) {
|
||||
// At some point one or more calls to exit have been made
|
||||
// we need to apply that exit mask the the current function scope's mask
|
||||
ll.apply_exit_to_mask_stack();
|
||||
@@ -1296,11 +1336,11 @@ BatchedBackendLLVM::llvm_generate_debugnan(const Opcode& op)
|
||||
if (op.opname() == op_aassign) {
|
||||
// Special case -- array assignment -- only check one element
|
||||
OSL_ASSERT(i == 0 && "only arg 0 is written for aassign");
|
||||
Symbol& index_sym = *opargsym(op, 1);
|
||||
llvm::Value* ind = llvm_load_value(index_sym);
|
||||
llvm::Value* agg = index_sym.is_uniform()
|
||||
? ll.constant(t.aggregate)
|
||||
: ll.wide_constant(t.aggregate);
|
||||
Symbol& index_sym = *opargsym(op, 1);
|
||||
llvm::Value* ind = llvm_load_value(index_sym);
|
||||
llvm::Value* agg = index_sym.is_uniform()
|
||||
? ll.constant(t.aggregate)
|
||||
: ll.wide_constant(t.aggregate);
|
||||
llvm::Value* scaled_offset = t.aggregate == 1 ? ind
|
||||
: ll.op_mul(ind, agg);
|
||||
if (index_sym.is_uniform()) {
|
||||
@@ -1471,9 +1511,9 @@ BatchedBackendLLVM::llvm_generate_debug_uninit(const Opcode& op)
|
||||
Symbol& index_sym = *opargsym(op, 2);
|
||||
llvm::Value* ind = llvm_load_value(index_sym);
|
||||
|
||||
llvm::Value* agg = index_sym.is_uniform()
|
||||
? ll.constant(t.aggregate)
|
||||
: ll.wide_constant(t.aggregate);
|
||||
llvm::Value* agg = index_sym.is_uniform()
|
||||
? ll.constant(t.aggregate)
|
||||
: ll.wide_constant(t.aggregate);
|
||||
llvm::Value* scaled_offset = t.aggregate == 1 ? ind
|
||||
: ll.op_mul(ind, agg);
|
||||
if (index_sym.is_uniform()) {
|
||||
@@ -1616,6 +1656,7 @@ BatchedBackendLLVM::llvm_generate_debug_uninit(const Opcode& op)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedBackendLLVM::llvm_generate_debug_op_printf(const Opcode& op)
|
||||
{
|
||||
@@ -1627,6 +1668,7 @@ BatchedBackendLLVM::llvm_generate_debug_op_printf(const Opcode& op)
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
BatchedBackendLLVM::build_llvm_code(int beginop, int endop,
|
||||
llvm::BasicBlock* bb)
|
||||
@@ -1670,8 +1712,9 @@ BatchedBackendLLVM::build_llvm_code(int beginop, int endop,
|
||||
} else if (op.opname() == op_nop || op.opname() == op_end) {
|
||||
// Skip this op, it does nothing...
|
||||
} else {
|
||||
shadingcontext()->errorfmt("LLVMOSL: Unsupported op {} in layer {}\n",
|
||||
op.opname(), inst()->layername());
|
||||
shadingcontext()->errorfmt(
|
||||
"LLVMOSL: Unsupported op {} in layer {}\n", op.opname(),
|
||||
inst()->layername());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1693,18 +1736,18 @@ BatchedBackendLLVM::build_llvm_init()
|
||||
// Make a group init function: void group_init(ShaderGlobals*, GroupData*)
|
||||
// Note that the GroupData* is passed as a void*.
|
||||
OSL_ASSERT(m_library_selector);
|
||||
std::string unique_name = Strutil::sprintf("%s_group_%d_init",
|
||||
m_library_selector,
|
||||
group().id());
|
||||
ll.current_function(ll.make_function(unique_name, false,
|
||||
ll.type_void(), // return type
|
||||
{ llvm_type_sg_ptr(),
|
||||
llvm_type_groupdata_ptr(),
|
||||
static_cast<llvm::Type *>(ll.type_void_ptr()), // wide_shader_index
|
||||
static_cast<llvm::Type *>(ll.type_void_ptr()), // userdata_base_ptr
|
||||
static_cast<llvm::Type *>(ll.type_void_ptr()), // output_base_ptr
|
||||
ll.type_int() // mask
|
||||
}));
|
||||
std::string unique_name = fmtformat("{}_group_{}_init", m_library_selector,
|
||||
group().id());
|
||||
ll.current_function(ll.make_function(
|
||||
unique_name, false,
|
||||
ll.type_void(), // return type
|
||||
{
|
||||
llvm_type_sg_ptr(), llvm_type_groupdata_ptr(),
|
||||
static_cast<llvm::Type*>(ll.type_void_ptr()), // wide_shader_index
|
||||
static_cast<llvm::Type*>(ll.type_void_ptr()), // userdata_base_ptr
|
||||
static_cast<llvm::Type*>(ll.type_void_ptr()), // output_base_ptr
|
||||
ll.type_int() // mask
|
||||
}));
|
||||
|
||||
if (ll.debug_is_enabled()) {
|
||||
ustring file_name
|
||||
@@ -1714,11 +1757,11 @@ BatchedBackendLLVM::build_llvm_init()
|
||||
}
|
||||
|
||||
// Get shader globals and groupdata pointers
|
||||
m_llvm_shaderglobals_ptr = ll.current_function_arg(0); //arg_it++;
|
||||
m_llvm_groupdata_ptr = ll.current_function_arg(1); //arg_it++;
|
||||
m_llvm_wide_shadeindex_ptr = ll.current_function_arg(2); //arg_it++;
|
||||
m_llvm_userdata_base_ptr = ll.current_function_arg(3); //arg_it++;
|
||||
m_llvm_output_base_ptr = ll.current_function_arg(4); //arg_it++;
|
||||
m_llvm_shaderglobals_ptr = ll.current_function_arg(0); //arg_it++;
|
||||
m_llvm_groupdata_ptr = ll.current_function_arg(1); //arg_it++;
|
||||
m_llvm_wide_shadeindex_ptr = ll.current_function_arg(2); //arg_it++;
|
||||
m_llvm_userdata_base_ptr = ll.current_function_arg(3); //arg_it++;
|
||||
m_llvm_output_base_ptr = ll.current_function_arg(4); //arg_it++;
|
||||
|
||||
// TODO: do we need to utilize the shader mask in the init function?
|
||||
//llvm::Value * llvm_initial_shader_mask_value = ll.current_function_arg(5); //arg_it++;
|
||||
@@ -1733,14 +1776,16 @@ BatchedBackendLLVM::build_llvm_init()
|
||||
ll.new_builder(entry_bb);
|
||||
|
||||
// Fixup type of wide shadeindex, we had to wait until we were in a basic block
|
||||
m_llvm_wide_shadeindex_ptr = ll.ptr_cast(m_llvm_wide_shadeindex_ptr, ll.type_wide_int_ptr()); //arg_it++;
|
||||
m_llvm_wide_shadeindex_ptr
|
||||
= ll.ptr_cast(m_llvm_wide_shadeindex_ptr,
|
||||
ll.type_wide_int_ptr()); //arg_it++;
|
||||
|
||||
ll.assume_ptr_is_aligned(m_llvm_shaderglobals_ptr, 64);
|
||||
ll.assume_ptr_is_aligned(m_llvm_groupdata_ptr, 64);
|
||||
|
||||
#if 0 /* helpful for debugging */
|
||||
if (llvm_debug()) {
|
||||
llvm_gen_debug_printf (Strutil::sprintf("\n\n\n\nGROUP! %s",group().name()));
|
||||
llvm_gen_debug_printf (fmtformat("\n\n\n\nGROUP! {}",group().name()));
|
||||
llvm_gen_debug_printf ("enter group initlayer %d %s %s"); this->layer(), inst()->layername(), inst()->shadername()));
|
||||
}
|
||||
#endif
|
||||
@@ -1770,6 +1815,8 @@ BatchedBackendLLVM::build_llvm_init()
|
||||
if (sym.typespec().is_closure_based()) {
|
||||
int arraylen = std::max(1, sym.typespec().arraylength());
|
||||
llvm::Value* val = ll.constant_ptr(NULL, ll.type_void_ptr());
|
||||
if (!sym.is_uniform())
|
||||
val = ll.widen_value(val);
|
||||
for (int a = 0; a < arraylen; ++a) {
|
||||
llvm::Value* arrind = sym.typespec().is_array()
|
||||
? ll.constant(a)
|
||||
@@ -1780,19 +1827,16 @@ BatchedBackendLLVM::build_llvm_init()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// All done
|
||||
#if 0 /* helpful for debugging */
|
||||
if (llvm_debug())
|
||||
llvm_gen_debug_printf (Strutil::sprintf("exit group init %s",
|
||||
group().name());
|
||||
llvm_gen_debug_printf(fmtformat("exit group init {}", group().name());
|
||||
#endif
|
||||
ll.op_return();
|
||||
|
||||
if (llvm_debug())
|
||||
std::cout << "group init func (" << unique_name << ") "
|
||||
<< " after llvm = "
|
||||
<< ll.bitcode_string(ll.current_function()) << "\n";
|
||||
OSL::print("group init func ({}) after llvm = {}\n", unique_name,
|
||||
ll.bitcode_string(ll.current_function()));
|
||||
|
||||
if (ll.debug_is_enabled()) {
|
||||
ll.debug_pop_function();
|
||||
@@ -1811,6 +1855,7 @@ BatchedBackendLLVM::build_llvm_init()
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Function*
|
||||
BatchedBackendLLVM::build_llvm_instance(bool groupentry)
|
||||
{
|
||||
@@ -1818,35 +1863,35 @@ BatchedBackendLLVM::build_llvm_instance(bool groupentry)
|
||||
// Note that the GroupData* is passed as a void*.
|
||||
OSL_ASSERT(m_library_selector);
|
||||
std::string unique_layer_name
|
||||
= Strutil::sprintf("%s_%s%s", m_library_selector,
|
||||
(groupentry ? "__direct_callable__" : ""),
|
||||
layer_function_name().c_str());
|
||||
= fmtformat("{}_{}{}", m_library_selector,
|
||||
(groupentry ? "__direct_callable__" : ""),
|
||||
layer_function_name());
|
||||
|
||||
bool is_entry_layer = group().is_entry_layer(layer());
|
||||
ll.current_function(
|
||||
ll.make_function(unique_layer_name,
|
||||
!is_entry_layer, // fastcall for non-entry layer functions
|
||||
ll.type_void(), // return type
|
||||
{ llvm_type_sg_ptr(), llvm_type_groupdata_ptr(),
|
||||
static_cast<llvm::Type *>(ll.type_void_ptr()), // wide_shader_index
|
||||
static_cast<llvm::Type *>(ll.type_void_ptr()), // userdata_base_ptr
|
||||
static_cast<llvm::Type *>(ll.type_void_ptr()), // output_base_ptr
|
||||
ll.type_int() // mask
|
||||
}));
|
||||
ll.current_function(ll.make_function(
|
||||
unique_layer_name,
|
||||
!is_entry_layer, // fastcall for non-entry layer functions
|
||||
ll.type_void(), // return type
|
||||
{
|
||||
llvm_type_sg_ptr(), llvm_type_groupdata_ptr(),
|
||||
static_cast<llvm::Type*>(ll.type_void_ptr()), // wide_shader_index
|
||||
static_cast<llvm::Type*>(ll.type_void_ptr()), // userdata_base_ptr
|
||||
static_cast<llvm::Type*>(ll.type_void_ptr()), // output_base_ptr
|
||||
ll.type_int() // mask
|
||||
}));
|
||||
|
||||
if (ll.debug_is_enabled()) {
|
||||
const Opcode& mainbegin (inst()->op(inst()->maincodebegin()));
|
||||
const Opcode& mainbegin(inst()->op(inst()->maincodebegin()));
|
||||
ll.debug_push_function(unique_layer_name, mainbegin.sourcefile(),
|
||||
mainbegin.sourceline());
|
||||
}
|
||||
|
||||
|
||||
// Get shader globals and groupdata pointers
|
||||
m_llvm_shaderglobals_ptr = ll.current_function_arg(0); //arg_it++;
|
||||
m_llvm_groupdata_ptr = ll.current_function_arg(1); //arg_it++;
|
||||
m_llvm_wide_shadeindex_ptr = ll.current_function_arg(2); //arg_it++;
|
||||
m_llvm_userdata_base_ptr = ll.current_function_arg(3); //arg_it++;
|
||||
m_llvm_output_base_ptr = ll.current_function_arg(4); //arg_it++;
|
||||
m_llvm_shaderglobals_ptr = ll.current_function_arg(0); //arg_it++;
|
||||
m_llvm_groupdata_ptr = ll.current_function_arg(1); //arg_it++;
|
||||
m_llvm_wide_shadeindex_ptr = ll.current_function_arg(2); //arg_it++;
|
||||
m_llvm_userdata_base_ptr = ll.current_function_arg(3); //arg_it++;
|
||||
m_llvm_output_base_ptr = ll.current_function_arg(4); //arg_it++;
|
||||
|
||||
llvm::Value* llvm_initial_shader_mask_value = ll.current_function_arg(
|
||||
5); //arg_it++;
|
||||
@@ -1863,7 +1908,9 @@ BatchedBackendLLVM::build_llvm_instance(bool groupentry)
|
||||
ll.new_builder(entry_bb);
|
||||
|
||||
// Fixup type of wide shadeindex, we had to wait until we were in a basic block
|
||||
m_llvm_wide_shadeindex_ptr = ll.ptr_cast(m_llvm_wide_shadeindex_ptr, ll.type_wide_int_ptr()); //arg_it++;
|
||||
m_llvm_wide_shadeindex_ptr
|
||||
= ll.ptr_cast(m_llvm_wide_shadeindex_ptr,
|
||||
ll.type_wide_int_ptr()); //arg_it++;
|
||||
|
||||
ll.assume_ptr_is_aligned(m_llvm_shaderglobals_ptr, 64);
|
||||
ll.assume_ptr_is_aligned(m_llvm_groupdata_ptr, 64);
|
||||
@@ -1898,16 +1945,17 @@ BatchedBackendLLVM::build_llvm_instance(bool groupentry)
|
||||
// and then run the layer.
|
||||
if (shadingsys().llvm_debug_layers())
|
||||
llvm_gen_debug_printf(
|
||||
Strutil::sprintf("checking for already-run layer %d %s %s",
|
||||
this->layer(), inst()->layername(),
|
||||
inst()->shadername()));
|
||||
fmtformat("checking for already-run layer {} {} {}",
|
||||
this->layer(), inst()->layername(),
|
||||
inst()->shadername()));
|
||||
llvm::Value* previously_executed = ll.int_as_mask(
|
||||
previously_executed_value);
|
||||
llvm::Value* required_lanes_executed
|
||||
= ll.op_select(initial_shader_mask, previously_executed,
|
||||
ll.wide_constant_bool(false));
|
||||
llvm::Value* all_required_lanes_already_executed
|
||||
= ll.op_eq(ll.mask_as_int(initial_shader_mask), ll.mask_as_int(required_lanes_executed));
|
||||
= ll.op_eq(ll.mask_as_int(initial_shader_mask),
|
||||
ll.mask_as_int(required_lanes_executed));
|
||||
|
||||
llvm::BasicBlock* then_block = ll.new_basic_block();
|
||||
llvm::BasicBlock* after_block = ll.new_basic_block();
|
||||
@@ -1916,17 +1964,17 @@ BatchedBackendLLVM::build_llvm_instance(bool groupentry)
|
||||
// insert point is now then_block
|
||||
// we've already executed, so return early
|
||||
if (shadingsys().llvm_debug_layers())
|
||||
llvm_gen_debug_printf(Strutil::sprintf(
|
||||
" taking early exit, already executed layer %d %s %s",
|
||||
llvm_gen_debug_printf(fmtformat(
|
||||
" taking early exit, already executed layer {} {} {}",
|
||||
this->layer(), inst()->layername(), inst()->shadername()));
|
||||
ll.op_return();
|
||||
ll.set_insert_point(after_block);
|
||||
}
|
||||
|
||||
if (shadingsys().llvm_debug_layers())
|
||||
llvm_gen_debug_printf(
|
||||
Strutil::sprintf("enter layer %d %s %s", this->layer(),
|
||||
inst()->layername(), inst()->shadername()));
|
||||
llvm_gen_debug_printf(fmtformat("enter layer {} {} {}", this->layer(),
|
||||
inst()->layername(),
|
||||
inst()->shadername()));
|
||||
// Mark this layer as executed
|
||||
if (!group().is_last_layer(layer())) {
|
||||
// Caller may only be asking for a subset of the lanes to be executed
|
||||
@@ -1970,8 +2018,8 @@ BatchedBackendLLVM::build_llvm_instance(bool groupentry)
|
||||
// If debugnan is turned on, globals check that their values are ok
|
||||
if (s.symtype() == SymTypeGlobal && shadingsys().debug_nan()) {
|
||||
TypeDesc t = s.typespec().simpletype();
|
||||
if (t.basetype
|
||||
== TypeDesc::FLOAT) { // just check float-based types
|
||||
if (t.basetype == TypeDesc::FLOAT) {
|
||||
// just check float-based types
|
||||
int ncomps = t.numelements() * t.aggregate;
|
||||
if (s.is_uniform()) {
|
||||
llvm::Value* args[]
|
||||
@@ -2112,8 +2160,8 @@ BatchedBackendLLVM::build_llvm_instance(bool groupentry)
|
||||
if (child->symbol(next.dst.param)
|
||||
== dstsym) {
|
||||
if (next.dst.channel != -1) {
|
||||
OSL_DASSERT(next.dst.channel
|
||||
< (int)inited.size());
|
||||
OSL_DASSERT(next.dst.channel
|
||||
< (int)inited.size());
|
||||
if (!inited[next.dst.channel]) {
|
||||
inited[next.dst.channel] = true;
|
||||
--ninit;
|
||||
@@ -2147,52 +2195,54 @@ BatchedBackendLLVM::build_llvm_instance(bool groupentry)
|
||||
// llvm_gen_debug_printf ("done copying connections");
|
||||
}
|
||||
|
||||
|
||||
// Copy results to renderer outputs
|
||||
// The current mask could be altered by early returns or exit
|
||||
// But for copying output parameters to output locations,
|
||||
// we want to use the shader mask
|
||||
ll.push_mask(initial_shader_mask, /*negate=*/false,
|
||||
/*absolute = */ true);
|
||||
FOREACH_PARAM(Symbol& s, inst()) {
|
||||
if (! s.renderer_output()) // Skip if not a renderer output
|
||||
FOREACH_PARAM(Symbol & s, inst())
|
||||
{
|
||||
if (!s.renderer_output()) // Skip if not a renderer output
|
||||
continue;
|
||||
// Try to look up the sym among the outputs with the full layer.name
|
||||
// specification first. If that fails, look for name only.
|
||||
ustring layersym = ustring::fmtformat("{}.{}", inst()->layername(),
|
||||
s.name());
|
||||
auto symloc = group().find_symloc(layersym, SymArena::Outputs);
|
||||
if (! symloc)
|
||||
auto symloc = group().find_symloc(layersym, SymArena::Outputs);
|
||||
if (!symloc)
|
||||
symloc = group().find_symloc(s.name(), SymArena::Outputs);
|
||||
if (! symloc) {
|
||||
if (!symloc) {
|
||||
// std::cout << "No output copy for " << s.name()
|
||||
// << " because no symloc was found\n";
|
||||
continue; // not found in either place
|
||||
continue; // not found in either place
|
||||
}
|
||||
|
||||
if (! equivalent(s.typespec(), symloc->type)
|
||||
if (!equivalent(s.typespec(), symloc->type)
|
||||
|| s.typespec().is_closure()) {
|
||||
std::cout << "No output copy for " << s.typespec() << ' ' << s.name()
|
||||
<< " because of type mismatch vs symloc=" << symloc->type
|
||||
<< "\n";
|
||||
// print("No output copy for {} {} because of type mismatch vs symloc={}\n",
|
||||
// s.typespec(), s.name(), symloc->type);
|
||||
continue; // types didn't match
|
||||
}
|
||||
auto type = s.typespec().simpletype();
|
||||
|
||||
//const int deriv_count = (symloc->derivs && s.has_derivs()) ? 3 : 1;
|
||||
const int output_deriv_count = symloc->derivs ? 3 : 1;
|
||||
const int s_deriv_count = s.has_derivs() ? 3 : 1;
|
||||
const int s_deriv_count = s.has_derivs() ? 3 : 1;
|
||||
|
||||
llvm::Value* sym_offset = ll.constanti64(symloc->offset);
|
||||
llvm::Value* output_sym_base_ptr = ll.ptr_cast(ll.offset_ptr(m_llvm_output_base_ptr, sym_offset), type.scalartype());
|
||||
llvm::Value* output_sym_base_ptr
|
||||
= ll.ptr_cast(ll.offset_ptr(m_llvm_output_base_ptr, sym_offset),
|
||||
type.scalartype());
|
||||
bool isBase32bit = (symloc->type != TypeDesc::STRING);
|
||||
int bytesPerElem = isBase32bit ? 4 : 8;
|
||||
// TODO: could move assert inside SymLocation
|
||||
OSL_ASSERT((symloc->stride % bytesPerElem) == 0);
|
||||
|
||||
|
||||
llvm::Value* wide_shadeindex = ll.op_load(ll.type_wide_int(), m_llvm_wide_shadeindex_ptr);
|
||||
const int elem_stride = static_cast<int>(symloc->stride/bytesPerElem);
|
||||
llvm::Value* wide_shadeindex = ll.op_load(ll.type_wide_int(),
|
||||
m_llvm_wide_shadeindex_ptr);
|
||||
const int elem_stride = static_cast<int>(symloc->stride / bytesPerElem);
|
||||
llvm::Value* wide_index_to_output = nullptr;
|
||||
if (elem_stride == 1) {
|
||||
wide_index_to_output = wide_shadeindex;
|
||||
@@ -2201,8 +2251,8 @@ BatchedBackendLLVM::build_llvm_instance(bool groupentry)
|
||||
wide_index_to_output = ll.op_mul(element_stride, wide_shadeindex);
|
||||
}
|
||||
|
||||
const int elem_count = static_cast<int>(type.numelements());
|
||||
const int comp_count = type.aggregate;
|
||||
const int elem_count = static_cast<int>(type.numelements());
|
||||
const int comp_count = type.aggregate;
|
||||
|
||||
int c = 0;
|
||||
for (int d = 0; d < output_deriv_count; ++d) {
|
||||
@@ -2213,16 +2263,17 @@ BatchedBackendLLVM::build_llvm_instance(bool groupentry)
|
||||
for (int i = 0; i < comp_count; ++i, ++c) {
|
||||
// It is fine if the symbol is uniform, it will get broadcast
|
||||
// to a wide value for use in the scatter.
|
||||
llvm::Value *wide_val = s_deriv_exists
|
||||
? llvm_load_value(s, d,
|
||||
arrind, /*component*/i,
|
||||
TypeDesc::UNKNOWN,
|
||||
/*op_is_uniform*/false)
|
||||
: ll.wide_constant(0.0f);
|
||||
llvm::Value* wide_val
|
||||
= s_deriv_exists
|
||||
? llvm_load_value(s, d, arrind, /*component*/ i,
|
||||
TypeDesc::UNKNOWN,
|
||||
/*op_is_uniform*/ false)
|
||||
: ll.wide_constant(0.0f);
|
||||
|
||||
llvm::Value* wide_index = wide_index_to_output;
|
||||
if (c != 0) {
|
||||
wide_index = ll.op_add(wide_index_to_output, ll.wide_constant(c));
|
||||
wide_index = ll.op_add(wide_index_to_output,
|
||||
ll.wide_constant(c));
|
||||
}
|
||||
ll.op_scatter(wide_val, output_sym_base_ptr, wide_index);
|
||||
}
|
||||
@@ -2233,9 +2284,9 @@ BatchedBackendLLVM::build_llvm_instance(bool groupentry)
|
||||
|
||||
// All done
|
||||
if (shadingsys().llvm_debug_layers())
|
||||
llvm_gen_debug_printf(
|
||||
Strutil::sprintf("exit layer %d %s %s", this->layer(),
|
||||
inst()->layername(), inst()->shadername()));
|
||||
llvm_gen_debug_printf(fmtformat("exit layer {} {} {}", this->layer(),
|
||||
inst()->layername(),
|
||||
inst()->shadername()));
|
||||
ll.op_return();
|
||||
|
||||
if (llvm_debug())
|
||||
@@ -2269,7 +2320,6 @@ BatchedBackendLLVM::initialize_llvm_group()
|
||||
const char* compile_unit_name = m_group.m_name.empty()
|
||||
? unknown_shader_group_name.c_str()
|
||||
: m_group.m_name.c_str();
|
||||
|
||||
ll.debug_setup_compilation_unit(compile_unit_name);
|
||||
}
|
||||
|
||||
@@ -2355,6 +2405,8 @@ BatchedBackendLLVM::initialize_llvm_group()
|
||||
m_llvm_type_setup_closure_func = m_llvm_type_prepare_closure_func;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
void
|
||||
BatchedBackendLLVM::build_offsets_of_BatchedShaderGlobals(
|
||||
@@ -2373,8 +2425,6 @@ BatchedBackendLLVM::build_offsets_of_BatchedShaderGlobals(
|
||||
+ offsetof(UniformShaderGlobals, context));
|
||||
offset_by_index.push_back(uniform_offset
|
||||
+ offsetof(UniformShaderGlobals, renderer));
|
||||
offset_by_index.push_back(uniform_offset
|
||||
+ offsetof(UniformShaderGlobals, Ci));
|
||||
offset_by_index.push_back(uniform_offset
|
||||
+ offsetof(UniformShaderGlobals, raytype));
|
||||
offset_by_index.push_back(uniform_offset
|
||||
@@ -2383,6 +2433,10 @@ BatchedBackendLLVM::build_offsets_of_BatchedShaderGlobals(
|
||||
+ offsetof(UniformShaderGlobals, pad1));
|
||||
offset_by_index.push_back(uniform_offset
|
||||
+ offsetof(UniformShaderGlobals, pad2));
|
||||
offset_by_index.push_back(uniform_offset
|
||||
+ offsetof(UniformShaderGlobals, pad3));
|
||||
offset_by_index.push_back(uniform_offset
|
||||
+ offsetof(UniformShaderGlobals, pad4));
|
||||
|
||||
offset_by_index.push_back(varying_offset
|
||||
+ offsetof(VaryingShaderGlobals<WidthT>, P));
|
||||
@@ -2429,6 +2483,8 @@ BatchedBackendLLVM::build_offsets_of_BatchedShaderGlobals(
|
||||
varying_offset + offsetof(VaryingShaderGlobals<WidthT>, object2common));
|
||||
offset_by_index.push_back(
|
||||
varying_offset + offsetof(VaryingShaderGlobals<WidthT>, shader2common));
|
||||
offset_by_index.push_back(varying_offset
|
||||
+ offsetof(VaryingShaderGlobals<WidthT>, Ci));
|
||||
offset_by_index.push_back(
|
||||
varying_offset + offsetof(VaryingShaderGlobals<WidthT>, surfacearea));
|
||||
offset_by_index.push_back(
|
||||
@@ -2439,6 +2495,7 @@ BatchedBackendLLVM::build_offsets_of_BatchedShaderGlobals(
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
void
|
||||
BatchedBackendLLVM::build_offsets_of_BatchedTextureOptions(
|
||||
@@ -2459,8 +2516,8 @@ BatchedBackendLLVM::build_offsets_of_BatchedTextureOptions(
|
||||
offset_by_index.push_back(
|
||||
varying_offset + offsetof(VaryingTextureOptions<WidthT>, rwidth));
|
||||
#if OIIO_VERSION_GREATER_EQUAL(2, 4, 0)
|
||||
offset_by_index.push_back(
|
||||
varying_offset + offsetof(VaryingTextureOptions<WidthT>, rnd));
|
||||
offset_by_index.push_back(varying_offset
|
||||
+ offsetof(VaryingTextureOptions<WidthT>, rnd));
|
||||
#endif
|
||||
offset_by_index.push_back(uniform_offset
|
||||
+ offsetof(UniformTextureOptions, firstchannel));
|
||||
@@ -2490,6 +2547,8 @@ BatchedBackendLLVM::build_offsets_of_BatchedTextureOptions(
|
||||
offsetof(BatchedTextureOptions<WidthT>, private_envlayout));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BatchedBackendLLVM::run()
|
||||
{
|
||||
@@ -2600,7 +2659,6 @@ BatchedBackendLLVM::run()
|
||||
ll.validate_struct_data_layout(m_llvm_type_sg, offset_by_index);
|
||||
}
|
||||
|
||||
|
||||
std::vector<llvm::Function*> funcs(nlayers, NULL);
|
||||
for (int layer = 0; layer < nlayers; ++layer) {
|
||||
set_inst(layer);
|
||||
@@ -2633,21 +2691,9 @@ 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.
|
||||
@@ -2656,7 +2702,6 @@ 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()) {
|
||||
@@ -2665,11 +2710,10 @@ BatchedBackendLLVM::run()
|
||||
std::string safegroup = Strutil::replace(group().name(), "/", ".",
|
||||
true);
|
||||
if (safegroup.size() > 235)
|
||||
safegroup
|
||||
= Strutil::sprintf("TRUNC_%s_%d",
|
||||
safegroup.substr(safegroup.size() - 235),
|
||||
group().id());
|
||||
std::string name = Strutil::sprintf("%s.ll", safegroup);
|
||||
safegroup = fmtformat("TRUNC_{}_{}",
|
||||
safegroup.substr(safegroup.size() - 235),
|
||||
group().id());
|
||||
std::string name = fmtformat("{}.ll", safegroup);
|
||||
std::ofstream out(name, std::ios_base::out | std::ios_base::trunc);
|
||||
if (out.good()) {
|
||||
out << ll.bitcode_string(ll.module());
|
||||
@@ -2711,11 +2755,10 @@ BatchedBackendLLVM::run()
|
||||
std::string safegroup = Strutil::replace(group().name(), "/", ".",
|
||||
true);
|
||||
if (safegroup.size() > 235)
|
||||
safegroup
|
||||
= Strutil::sprintf("TRUNC_%s_%d",
|
||||
safegroup.substr(safegroup.size() - 235),
|
||||
group().id());
|
||||
std::string name = Strutil::sprintf("%s_opt.ll", safegroup);
|
||||
safegroup = fmtformat("TRUNC_{}_{}",
|
||||
safegroup.substr(safegroup.size() - 235),
|
||||
group().id());
|
||||
std::string name = fmtformat("{}_opt.ll", safegroup);
|
||||
std::ofstream out(name, std::ios_base::out | std::ios_base::trunc);
|
||||
if (out.good()) {
|
||||
out << ll.bitcode_string(ll.module());
|
||||
@@ -2755,9 +2798,9 @@ BatchedBackendLLVM::run()
|
||||
m_stat_total_llvm_time = timer();
|
||||
|
||||
if (shadingsys().m_compile_report) {
|
||||
shadingcontext()->infof("JITed shader group %s:", group().name());
|
||||
shadingcontext()->infof(
|
||||
" (%1.2fs = %1.2f setup, %1.2f ir, %1.2f opt, %1.2f jit; local mem %dKB)",
|
||||
shadingcontext()->infofmt("JITed shader group {}:", group().name());
|
||||
shadingcontext()->infofmt(
|
||||
" ({:1.2f}s = {:1.2f} setup, {:1.2f} ir, {:1.2f} opt, {:1.2f} jit; local mem {}KB)",
|
||||
m_stat_total_llvm_time, m_stat_llvm_setup_time,
|
||||
m_stat_llvm_irgen_time, m_stat_llvm_opt_time, m_stat_llvm_jit_time,
|
||||
m_llvm_local_mem / 1024);
|
||||
@@ -2765,6 +2808,5 @@ BatchedBackendLLVM::run()
|
||||
}
|
||||
|
||||
|
||||
|
||||
}; // namespace pvt
|
||||
OSL_NAMESPACE_EXIT
|
||||
|
||||
@@ -13,6 +13,7 @@ using namespace OSL::pvt;
|
||||
|
||||
OSL_NAMESPACE_ENTER
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
BatchedRendererServices<WidthT>::BatchedRendererServices(TextureSystem* texsys)
|
||||
: m_texturesys(texsys)
|
||||
@@ -35,6 +36,7 @@ BatchedRendererServices<WidthT>::BatchedRendererServices(TextureSystem* texsys)
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
Mask<WidthT>
|
||||
BatchedRendererServices<WidthT>::get_matrix(BatchedShaderGlobals* bsg,
|
||||
@@ -49,6 +51,7 @@ BatchedRendererServices<WidthT>::get_matrix(BatchedShaderGlobals* bsg,
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
Mask<WidthT>
|
||||
BatchedRendererServices<WidthT>::get_inverse_matrix(
|
||||
@@ -62,6 +65,7 @@ BatchedRendererServices<WidthT>::get_inverse_matrix(
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
Mask<WidthT>
|
||||
BatchedRendererServices<WidthT>::get_inverse_matrix(BatchedShaderGlobals* bsg,
|
||||
@@ -75,6 +79,8 @@ BatchedRendererServices<WidthT>::get_inverse_matrix(BatchedShaderGlobals* bsg,
|
||||
return Mask(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
Mask<WidthT>
|
||||
BatchedRendererServices<WidthT>::get_inverse_matrix(BatchedShaderGlobals* bsg,
|
||||
@@ -88,6 +94,8 @@ BatchedRendererServices<WidthT>::get_inverse_matrix(BatchedShaderGlobals* bsg,
|
||||
return Mask(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
TextureSystem*
|
||||
BatchedRendererServices<WidthT>::texturesys() const
|
||||
@@ -95,6 +103,8 @@ BatchedRendererServices<WidthT>::texturesys() const
|
||||
return m_texturesys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
TextureSystem::TextureHandle*
|
||||
BatchedRendererServices<WidthT>::resolve_udim_uniform(
|
||||
@@ -107,7 +117,6 @@ 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.
|
||||
@@ -121,11 +130,13 @@ BatchedRendererServices<WidthT>::resolve_udim_uniform(
|
||||
udim_handle = texture_handle;
|
||||
}
|
||||
return udim_handle;
|
||||
} else
|
||||
#endif
|
||||
} else {
|
||||
return texture_handle;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
void
|
||||
BatchedRendererServices<WidthT>::resolve_udim(
|
||||
@@ -139,7 +150,6 @@ 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.
|
||||
@@ -155,12 +165,13 @@ BatchedRendererServices<WidthT>::resolve_udim(
|
||||
}
|
||||
wresult[l] = udim_handle;
|
||||
});
|
||||
} else
|
||||
#endif
|
||||
} else {
|
||||
assign_all(wresult, texture_handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
bool
|
||||
BatchedRendererServices<WidthT>::get_texture_info_uniform(
|
||||
@@ -180,13 +191,15 @@ BatchedRendererServices<WidthT>::get_texture_info_uniform(
|
||||
if (!status) {
|
||||
std::string err = texturesys()->geterror();
|
||||
if (err.size() && bsg) {
|
||||
bsg->uniform.context->errorf(
|
||||
"[RendererServices::get_texture_info] %s", err);
|
||||
bsg->uniform.context->errorfmt(
|
||||
"[RendererServices::get_texture_info] {}", err);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
Mask<WidthT>
|
||||
BatchedRendererServices<WidthT>::texture(
|
||||
@@ -203,6 +216,8 @@ BatchedRendererServices<WidthT>::texture(
|
||||
return Mask(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
Mask<WidthT>
|
||||
BatchedRendererServices<WidthT>::texture3d(
|
||||
@@ -218,6 +233,8 @@ BatchedRendererServices<WidthT>::texture3d(
|
||||
return Mask(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
Mask<WidthT>
|
||||
BatchedRendererServices<WidthT>::environment(
|
||||
@@ -233,6 +250,8 @@ BatchedRendererServices<WidthT>::environment(
|
||||
return Mask(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
void
|
||||
BatchedRendererServices<WidthT>::pointcloud_search(
|
||||
@@ -245,6 +264,8 @@ BatchedRendererServices<WidthT>::pointcloud_search(
|
||||
&& "UNREACHABLE: BatchedRendererServices<WidthT>::pointcloud_search calls should be overridden or the target specific version in wide_oppointcloud.cpp should be called");
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
Mask<WidthT>
|
||||
BatchedRendererServices<WidthT>::pointcloud_get(
|
||||
@@ -258,6 +279,7 @@ BatchedRendererServices<WidthT>::pointcloud_get(
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
Mask<WidthT>
|
||||
BatchedRendererServices<WidthT>::pointcloud_write(
|
||||
@@ -271,6 +293,8 @@ BatchedRendererServices<WidthT>::pointcloud_write(
|
||||
return Mask(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
void
|
||||
BatchedRendererServices<WidthT>::trace(
|
||||
@@ -283,6 +307,8 @@ BatchedRendererServices<WidthT>::trace(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int WidthT>
|
||||
void
|
||||
BatchedRendererServices<WidthT>::getmessage(BatchedShaderGlobals* bsg,
|
||||
@@ -296,6 +322,8 @@ BatchedRendererServices<WidthT>::getmessage(BatchedShaderGlobals* bsg,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Explicitly instantiate BatchedRendererServices template
|
||||
template class OSLEXECPUBLIC BatchedRendererServices<16>;
|
||||
template class OSLEXECPUBLIC BatchedRendererServices<8>;
|
||||
|
||||
+276
-277
@@ -11,119 +11,118 @@
|
||||
|
||||
|
||||
#ifndef DECL
|
||||
#error Do not include this file unless DECL is defined
|
||||
# error Do not include this file unless DECL is defined
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define NOISE_IMPL(name) \
|
||||
DECL (osl_ ## name ## _ff, "ff") \
|
||||
DECL (osl_ ## name ## _fff, "fff") \
|
||||
DECL (osl_ ## name ## _fv, "fv") \
|
||||
DECL (osl_ ## name ## _fvf, "fvf") \
|
||||
DECL (osl_ ## name ## _vf, "xvf") \
|
||||
DECL (osl_ ## name ## _vff, "xvff") \
|
||||
DECL (osl_ ## name ## _vv, "xvv") \
|
||||
DECL (osl_ ## name ## _vvf, "xvvf")
|
||||
#define NOISE_IMPL(name) \
|
||||
DECL(osl_##name##_ff, "ff") \
|
||||
DECL(osl_##name##_fff, "fff") \
|
||||
DECL(osl_##name##_fv, "fv") \
|
||||
DECL(osl_##name##_fvf, "fvf") \
|
||||
DECL(osl_##name##_vf, "xvf") \
|
||||
DECL(osl_##name##_vff, "xvff") \
|
||||
DECL(osl_##name##_vv, "xvv") \
|
||||
DECL(osl_##name##_vvf, "xvvf")
|
||||
|
||||
#define NOISE_DERIV_IMPL(name) \
|
||||
DECL (osl_ ## name ## _dfdf, "xXX") \
|
||||
DECL (osl_ ## name ## _dfdff, "xXXf") \
|
||||
DECL (osl_ ## name ## _dffdf, "xXfX") \
|
||||
DECL (osl_ ## name ## _dfdfdf, "xXXX") \
|
||||
DECL (osl_ ## name ## _dfdv, "xXv") \
|
||||
DECL (osl_ ## name ## _dfdvf, "xXvf") \
|
||||
DECL (osl_ ## name ## _dfvdf, "xXvX") \
|
||||
DECL (osl_ ## name ## _dfdvdf, "xXvX") \
|
||||
DECL (osl_ ## name ## _dvdf, "xvX") \
|
||||
DECL (osl_ ## name ## _dvdff, "xvXf") \
|
||||
DECL (osl_ ## name ## _dvfdf, "xvfX") \
|
||||
DECL (osl_ ## name ## _dvdfdf, "xvXX") \
|
||||
DECL (osl_ ## name ## _dvdv, "xvv") \
|
||||
DECL (osl_ ## name ## _dvdvf, "xvvf") \
|
||||
DECL (osl_ ## name ## _dvvdf, "xvvX") \
|
||||
DECL (osl_ ## name ## _dvdvdf, "xvvX")
|
||||
#define NOISE_DERIV_IMPL(name) \
|
||||
DECL(osl_##name##_dfdf, "xXX") \
|
||||
DECL(osl_##name##_dfdff, "xXXf") \
|
||||
DECL(osl_##name##_dffdf, "xXfX") \
|
||||
DECL(osl_##name##_dfdfdf, "xXXX") \
|
||||
DECL(osl_##name##_dfdv, "xXv") \
|
||||
DECL(osl_##name##_dfdvf, "xXvf") \
|
||||
DECL(osl_##name##_dfvdf, "xXvX") \
|
||||
DECL(osl_##name##_dfdvdf, "xXvX") \
|
||||
DECL(osl_##name##_dvdf, "xvX") \
|
||||
DECL(osl_##name##_dvdff, "xvXf") \
|
||||
DECL(osl_##name##_dvfdf, "xvfX") \
|
||||
DECL(osl_##name##_dvdfdf, "xvXX") \
|
||||
DECL(osl_##name##_dvdv, "xvv") \
|
||||
DECL(osl_##name##_dvdvf, "xvvf") \
|
||||
DECL(osl_##name##_dvvdf, "xvvX") \
|
||||
DECL(osl_##name##_dvdvdf, "xvvX")
|
||||
|
||||
#define GENERIC_NOISE_DERIV_IMPL(name) \
|
||||
DECL (osl_ ## name ## _dfdf, "xsXXXX") \
|
||||
DECL (osl_ ## name ## _dfdfdf, "xsXXXXX") \
|
||||
DECL (osl_ ## name ## _dfdv, "xsXXXX") \
|
||||
DECL (osl_ ## name ## _dfdvdf, "xsXXXXX") \
|
||||
DECL (osl_ ## name ## _dvdf, "xsXXXX") \
|
||||
DECL (osl_ ## name ## _dvdfdf, "xsXXXXX") \
|
||||
DECL (osl_ ## name ## _dvdv, "xsXXXX") \
|
||||
DECL (osl_ ## name ## _dvdvdf, "xsXXXXX")
|
||||
#define GENERIC_NOISE_DERIV_IMPL(name) \
|
||||
DECL(osl_##name##_dfdf, "xsXXXX") \
|
||||
DECL(osl_##name##_dfdfdf, "xsXXXXX") \
|
||||
DECL(osl_##name##_dfdv, "xsXXXX") \
|
||||
DECL(osl_##name##_dfdvdf, "xsXXXXX") \
|
||||
DECL(osl_##name##_dvdf, "xsXXXX") \
|
||||
DECL(osl_##name##_dvdfdf, "xsXXXXX") \
|
||||
DECL(osl_##name##_dvdv, "xsXXXX") \
|
||||
DECL(osl_##name##_dvdvdf, "xsXXXXX")
|
||||
|
||||
#define PNOISE_IMPL(name) \
|
||||
DECL (osl_ ## name ## _fff, "fff") \
|
||||
DECL (osl_ ## name ## _fffff, "fffff") \
|
||||
DECL (osl_ ## name ## _fvv, "fvv") \
|
||||
DECL (osl_ ## name ## _fvfvf, "fvfvf") \
|
||||
DECL (osl_ ## name ## _vff, "xvff") \
|
||||
DECL (osl_ ## name ## _vffff, "xvffff") \
|
||||
DECL (osl_ ## name ## _vvv, "xvvv") \
|
||||
DECL (osl_ ## name ## _vvfvf, "xvvfvf")
|
||||
#define PNOISE_IMPL(name) \
|
||||
DECL(osl_##name##_fff, "fff") \
|
||||
DECL(osl_##name##_fffff, "fffff") \
|
||||
DECL(osl_##name##_fvv, "fvv") \
|
||||
DECL(osl_##name##_fvfvf, "fvfvf") \
|
||||
DECL(osl_##name##_vff, "xvff") \
|
||||
DECL(osl_##name##_vffff, "xvffff") \
|
||||
DECL(osl_##name##_vvv, "xvvv") \
|
||||
DECL(osl_##name##_vvfvf, "xvvfvf")
|
||||
|
||||
#define PNOISE_DERIV_IMPL(name) \
|
||||
DECL (osl_ ## name ## _dfdff, "xXXf") \
|
||||
DECL (osl_ ## name ## _dfdffff, "xXXfff") \
|
||||
DECL (osl_ ## name ## _dffdfff, "xXfXff") \
|
||||
DECL (osl_ ## name ## _dfdfdfff, "xXXXff") \
|
||||
DECL (osl_ ## name ## _dfdvv, "xXXv") \
|
||||
DECL (osl_ ## name ## _dfdvfvf, "xXvfvf") \
|
||||
DECL (osl_ ## name ## _dfvdfvf, "xXvXvf") \
|
||||
DECL (osl_ ## name ## _dfdvdfvf, "xXvXvf") \
|
||||
DECL (osl_ ## name ## _dvdff, "xvXf") \
|
||||
DECL (osl_ ## name ## _dvdffff, "xvXfff") \
|
||||
DECL (osl_ ## name ## _dvfdfff, "xvfXff") \
|
||||
DECL (osl_ ## name ## _dvdfdfff, "xvXXff") \
|
||||
DECL (osl_ ## name ## _dvdvv, "xvvv") \
|
||||
DECL (osl_ ## name ## _dvdvfvf, "xvvfvf") \
|
||||
DECL (osl_ ## name ## _dvvdfvf, "xvvXvf") \
|
||||
DECL (osl_ ## name ## _dvdvdfvf, "xvvXvf")
|
||||
#define PNOISE_DERIV_IMPL(name) \
|
||||
DECL(osl_##name##_dfdff, "xXXf") \
|
||||
DECL(osl_##name##_dfdffff, "xXXfff") \
|
||||
DECL(osl_##name##_dffdfff, "xXfXff") \
|
||||
DECL(osl_##name##_dfdfdfff, "xXXXff") \
|
||||
DECL(osl_##name##_dfdvv, "xXXv") \
|
||||
DECL(osl_##name##_dfdvfvf, "xXvfvf") \
|
||||
DECL(osl_##name##_dfvdfvf, "xXvXvf") \
|
||||
DECL(osl_##name##_dfdvdfvf, "xXvXvf") \
|
||||
DECL(osl_##name##_dvdff, "xvXf") \
|
||||
DECL(osl_##name##_dvdffff, "xvXfff") \
|
||||
DECL(osl_##name##_dvfdfff, "xvfXff") \
|
||||
DECL(osl_##name##_dvdfdfff, "xvXXff") \
|
||||
DECL(osl_##name##_dvdvv, "xvvv") \
|
||||
DECL(osl_##name##_dvdvfvf, "xvvfvf") \
|
||||
DECL(osl_##name##_dvvdfvf, "xvvXvf") \
|
||||
DECL(osl_##name##_dvdvdfvf, "xvvXvf")
|
||||
|
||||
#define GENERIC_PNOISE_DERIV_IMPL(name) \
|
||||
DECL (osl_ ## name ## _dfdff, "xsXXfXX") \
|
||||
DECL (osl_ ## name ## _dfdfdfff, "xsXXXffXX") \
|
||||
DECL (osl_ ## name ## _dfdvv, "xsXXvXX") \
|
||||
DECL (osl_ ## name ## _dfdvdfvf, "xsXvXvfXX") \
|
||||
DECL (osl_ ## name ## _dvdff, "xsvXfXX") \
|
||||
DECL (osl_ ## name ## _dvdfdfff, "xsvXXffXX") \
|
||||
DECL (osl_ ## name ## _dvdvv, "xsvvvXX") \
|
||||
DECL (osl_ ## name ## _dvdvdfvf, "xsvvXvfXX")
|
||||
#define GENERIC_PNOISE_DERIV_IMPL(name) \
|
||||
DECL(osl_##name##_dfdff, "xsXXfXX") \
|
||||
DECL(osl_##name##_dfdfdfff, "xsXXXffXX") \
|
||||
DECL(osl_##name##_dfdvv, "xsXXvXX") \
|
||||
DECL(osl_##name##_dfdvdfvf, "xsXvXvfXX") \
|
||||
DECL(osl_##name##_dvdff, "xsvXfXX") \
|
||||
DECL(osl_##name##_dvdfdfff, "xsvXXffXX") \
|
||||
DECL(osl_##name##_dvdvv, "xsvvvXX") \
|
||||
DECL(osl_##name##_dvdvdfvf, "xsvvXvfXX")
|
||||
|
||||
#define UNARY_OP_IMPL(name) \
|
||||
DECL (osl_ ## name ## _ff, "ff") \
|
||||
DECL (osl_ ## name ## _dfdf, "xXX") \
|
||||
DECL (osl_ ## name ## _vv, "xXX") \
|
||||
DECL (osl_ ## name ## _dvdv, "xXX")
|
||||
#define UNARY_OP_IMPL(name) \
|
||||
DECL(osl_##name##_ff, "ff") \
|
||||
DECL(osl_##name##_dfdf, "xXX") \
|
||||
DECL(osl_##name##_vv, "xXX") \
|
||||
DECL(osl_##name##_dvdv, "xXX")
|
||||
|
||||
#define BINARY_OP_IMPL(name) \
|
||||
DECL (osl_ ## name ## _fff, "fff") \
|
||||
DECL (osl_ ## name ## _dfdfdf, "xXXX") \
|
||||
DECL (osl_ ## name ## _dffdf, "xXfX") \
|
||||
DECL (osl_ ## name ## _dfdff, "xXXf") \
|
||||
DECL (osl_ ## name ## _vvv, "xXXX") \
|
||||
DECL (osl_ ## name ## _dvdvdv, "xXXX") \
|
||||
DECL (osl_ ## name ## _dvvdv, "xXXX") \
|
||||
DECL (osl_ ## name ## _dvdvv, "xXXX")
|
||||
#define BINARY_OP_IMPL(name) \
|
||||
DECL(osl_##name##_fff, "fff") \
|
||||
DECL(osl_##name##_dfdfdf, "xXXX") \
|
||||
DECL(osl_##name##_dffdf, "xXfX") \
|
||||
DECL(osl_##name##_dfdff, "xXXf") \
|
||||
DECL(osl_##name##_vvv, "xXXX") \
|
||||
DECL(osl_##name##_dvdvdv, "xXXX") \
|
||||
DECL(osl_##name##_dvvdv, "xXXX") \
|
||||
DECL(osl_##name##_dvdvv, "xXXX")
|
||||
|
||||
|
||||
|
||||
|
||||
DECL (osl_add_closure_closure, "CXCC")
|
||||
DECL (osl_mul_closure_float, "CXCf")
|
||||
DECL (osl_mul_closure_color, "CXCc")
|
||||
DECL (osl_allocate_closure_component, "CXii")
|
||||
DECL (osl_allocate_weighted_closure_component, "CXiiX")
|
||||
DECL (osl_closure_to_string, "sXC")
|
||||
DECL (osl_format, "ss*")
|
||||
DECL (osl_printf, "xXs*")
|
||||
DECL (osl_fprintf, "xXss*")
|
||||
DECL (osl_error, "xXs*")
|
||||
DECL (osl_warning, "xXs*")
|
||||
DECL (osl_split, "isXsii")
|
||||
DECL (osl_incr_layers_executed, "xX")
|
||||
DECL(osl_add_closure_closure, "CXCC")
|
||||
DECL(osl_mul_closure_float, "CXCf")
|
||||
DECL(osl_mul_closure_color, "CXCc")
|
||||
DECL(osl_allocate_closure_component, "CXii")
|
||||
DECL(osl_allocate_weighted_closure_component, "CXiiX")
|
||||
DECL(osl_closure_to_string, "sXC")
|
||||
DECL(osl_format, "ss*")
|
||||
DECL(osl_printf, "xXs*")
|
||||
DECL(osl_fprintf, "xXss*")
|
||||
DECL(osl_error, "xXs*")
|
||||
DECL(osl_warning, "xXs*")
|
||||
DECL(osl_split, "isXsii")
|
||||
DECL(osl_incr_layers_executed, "xX")
|
||||
|
||||
NOISE_IMPL(cellnoise)
|
||||
//NOISE_DERIV_IMPL(cellnoise)
|
||||
@@ -151,70 +150,70 @@ PNOISE_IMPL(psnoise)
|
||||
PNOISE_DERIV_IMPL(psnoise)
|
||||
GENERIC_PNOISE_DERIV_IMPL(gaborpnoise)
|
||||
GENERIC_PNOISE_DERIV_IMPL(genericpnoise)
|
||||
DECL (osl_noiseparams_set_anisotropic, "xXi")
|
||||
DECL (osl_noiseparams_set_do_filter, "xXi")
|
||||
DECL (osl_noiseparams_set_direction, "xXv")
|
||||
DECL (osl_noiseparams_set_bandwidth, "xXf")
|
||||
DECL (osl_noiseparams_set_impulses, "xXf")
|
||||
DECL (osl_count_noise, "xX")
|
||||
DECL (osl_hash_ii, "ii")
|
||||
DECL (osl_hash_if, "if")
|
||||
DECL (osl_hash_iff, "iff")
|
||||
DECL (osl_hash_iv, "iX")
|
||||
DECL (osl_hash_ivf, "iXf")
|
||||
DECL(osl_noiseparams_set_anisotropic, "xXi")
|
||||
DECL(osl_noiseparams_set_do_filter, "xXi")
|
||||
DECL(osl_noiseparams_set_direction, "xXv")
|
||||
DECL(osl_noiseparams_set_bandwidth, "xXf")
|
||||
DECL(osl_noiseparams_set_impulses, "xXf")
|
||||
DECL(osl_count_noise, "xX")
|
||||
DECL(osl_hash_ii, "ii")
|
||||
DECL(osl_hash_if, "if")
|
||||
DECL(osl_hash_iff, "iff")
|
||||
DECL(osl_hash_iv, "iX")
|
||||
DECL(osl_hash_ivf, "iXf")
|
||||
|
||||
DECL (osl_spline_fff, "xXXXXii")
|
||||
DECL (osl_spline_dfdfdf, "xXXXXii")
|
||||
DECL (osl_spline_dfdff, "xXXXXii")
|
||||
DECL (osl_spline_dffdf, "xXXXXii")
|
||||
DECL (osl_spline_vfv, "xXXXXii")
|
||||
DECL (osl_spline_dvdfdv, "xXXXXii")
|
||||
DECL (osl_spline_dvdfv, "xXXXXii")
|
||||
DECL (osl_spline_dvfdv, "xXXXXii")
|
||||
DECL (osl_splineinverse_fff, "xXXXXii")
|
||||
DECL (osl_splineinverse_dfdfdf, "xXXXXii")
|
||||
DECL (osl_splineinverse_dfdff, "xXXXXii")
|
||||
DECL (osl_splineinverse_dffdf, "xXXXXii")
|
||||
DECL (osl_setmessage, "xXsLXisi")
|
||||
DECL (osl_getmessage, "iXssLXiisi")
|
||||
DECL (osl_pointcloud_search, "iXsXfiiXXii*")
|
||||
DECL (osl_pointcloud_get, "iXsXisLX")
|
||||
DECL (osl_pointcloud_write, "iXsXiXXX")
|
||||
DECL (osl_pointcloud_write_helper, "xXXXisLX")
|
||||
DECL (osl_blackbody_vf, "xXXf")
|
||||
DECL (osl_wavelength_color_vf, "xXXf")
|
||||
DECL (osl_luminance_fv, "xXXX")
|
||||
DECL (osl_luminance_dfdv, "xXXX")
|
||||
DECL (osl_prepend_color_from, "xXXs")
|
||||
DECL (osl_prepend_matrix_from, "iXXs")
|
||||
DECL (osl_get_matrix, "iXXs")
|
||||
DECL (osl_get_inverse_matrix, "iXXs")
|
||||
DECL (osl_transform_triple, "iXXiXiXXi")
|
||||
DECL (osl_transform_triple_nonlinear, "iXXiXiXXi")
|
||||
DECL (osl_transform_vmv, "xXXX")
|
||||
DECL (osl_transform_dvmdv, "xXXX")
|
||||
DECL (osl_transformv_vmv, "xXXX")
|
||||
DECL (osl_transformv_dvmdv, "xXXX")
|
||||
DECL (osl_transformn_vmv, "xXXX")
|
||||
DECL (osl_transformn_dvmdv, "xXXX")
|
||||
DECL (osl_transformc, "iXXiXiXX")
|
||||
DECL(osl_spline_fff, "xXXXXii")
|
||||
DECL(osl_spline_dfdfdf, "xXXXXii")
|
||||
DECL(osl_spline_dfdff, "xXXXXii")
|
||||
DECL(osl_spline_dffdf, "xXXXXii")
|
||||
DECL(osl_spline_vfv, "xXXXXii")
|
||||
DECL(osl_spline_dvdfdv, "xXXXXii")
|
||||
DECL(osl_spline_dvdfv, "xXXXXii")
|
||||
DECL(osl_spline_dvfdv, "xXXXXii")
|
||||
DECL(osl_splineinverse_fff, "xXXXXii")
|
||||
DECL(osl_splineinverse_dfdfdf, "xXXXXii")
|
||||
DECL(osl_splineinverse_dfdff, "xXXXXii")
|
||||
DECL(osl_splineinverse_dffdf, "xXXXXii")
|
||||
DECL(osl_setmessage, "xXsLXisi")
|
||||
DECL(osl_getmessage, "iXssLXiisi")
|
||||
DECL(osl_pointcloud_search, "iXsXfiiXXii*")
|
||||
DECL(osl_pointcloud_get, "iXsXisLX")
|
||||
DECL(osl_pointcloud_write, "iXsXiXXX")
|
||||
DECL(osl_pointcloud_write_helper, "xXXXisLX")
|
||||
DECL(osl_blackbody_vf, "xXXf")
|
||||
DECL(osl_wavelength_color_vf, "xXXf")
|
||||
DECL(osl_luminance_fv, "xXXX")
|
||||
DECL(osl_luminance_dfdv, "xXXX")
|
||||
DECL(osl_prepend_color_from, "xXXs")
|
||||
DECL(osl_prepend_matrix_from, "iXXs")
|
||||
DECL(osl_get_matrix, "iXXs")
|
||||
DECL(osl_get_inverse_matrix, "iXXs")
|
||||
DECL(osl_transform_triple, "iXXiXiXXi")
|
||||
DECL(osl_transform_triple_nonlinear, "iXXiXiXXi")
|
||||
DECL(osl_transform_vmv, "xXXX")
|
||||
DECL(osl_transform_dvmdv, "xXXX")
|
||||
DECL(osl_transformv_vmv, "xXXX")
|
||||
DECL(osl_transformv_dvmdv, "xXXX")
|
||||
DECL(osl_transformn_vmv, "xXXX")
|
||||
DECL(osl_transformn_dvmdv, "xXXX")
|
||||
DECL(osl_transformc, "iXXiXiXX")
|
||||
|
||||
DECL (osl_dict_find_iis, "iXiX")
|
||||
DECL (osl_dict_find_iss, "iXXX")
|
||||
DECL (osl_dict_next, "iXi")
|
||||
DECL (osl_dict_value, "iXiXLX")
|
||||
DECL (osl_raytype_name, "iXs")
|
||||
DECL(osl_dict_find_iis, "iXiX")
|
||||
DECL(osl_dict_find_iss, "iXXX")
|
||||
DECL(osl_dict_next, "iXi")
|
||||
DECL(osl_dict_value, "iXiXLX")
|
||||
DECL(osl_raytype_name, "iXs")
|
||||
#ifdef OSL_LLVM_NO_BITCODE
|
||||
DECL (osl_range_check, "iiiXXXiXiXX")
|
||||
DECL(osl_range_check, "iiiXXXiXiXX")
|
||||
#endif
|
||||
DECL (osl_range_check_err, "iiiXXXiXiXX")
|
||||
DECL (osl_naninf_check, "xiXiXXiXiiX")
|
||||
DECL (osl_uninit_check, "xLXXXiXiXXiXiXii")
|
||||
DECL (osl_get_attribute, "iXiXXiiLX")
|
||||
DECL (osl_bind_interpolated_param, "iXXLiXiXiXi")
|
||||
DECL (osl_get_texture_options, "XX");
|
||||
DECL (osl_get_noise_options, "XX");
|
||||
DECL (osl_get_trace_options, "XX");
|
||||
DECL(osl_range_check_err, "iiiXXXiXiXX")
|
||||
DECL(osl_naninf_check, "xiXiXXiXiiX")
|
||||
DECL(osl_uninit_check, "xLXXXiXiXXiXiXii")
|
||||
DECL(osl_get_attribute, "iXiXXiiLX")
|
||||
DECL(osl_bind_interpolated_param, "iXXLiXiXiXi")
|
||||
DECL(osl_get_texture_options, "XX");
|
||||
DECL(osl_get_noise_options, "XX");
|
||||
DECL(osl_get_trace_options, "XX");
|
||||
|
||||
|
||||
// The following are defined inside llvm_ops.cpp. Only include these
|
||||
@@ -231,17 +230,17 @@ UNARY_OP_IMPL(sinh)
|
||||
UNARY_OP_IMPL(cosh)
|
||||
UNARY_OP_IMPL(tanh)
|
||||
|
||||
DECL (osl_safe_div_iii, "iii")
|
||||
DECL (osl_safe_div_fff, "fff")
|
||||
DECL (osl_safe_mod_iii, "iii")
|
||||
DECL (osl_sincos_fff, "xfXX")
|
||||
DECL (osl_sincos_dfdff, "xXXX")
|
||||
DECL (osl_sincos_dffdf, "xXXX")
|
||||
DECL (osl_sincos_dfdfdf, "xXXX")
|
||||
DECL (osl_sincos_vvv, "xXXX")
|
||||
DECL (osl_sincos_dvdvv, "xXXX")
|
||||
DECL (osl_sincos_dvvdv, "xXXX")
|
||||
DECL (osl_sincos_dvdvdv, "xXXX")
|
||||
DECL(osl_safe_div_iii, "iii")
|
||||
DECL(osl_safe_div_fff, "fff")
|
||||
DECL(osl_safe_mod_iii, "iii")
|
||||
DECL(osl_sincos_fff, "xfXX")
|
||||
DECL(osl_sincos_dfdff, "xXXX")
|
||||
DECL(osl_sincos_dffdf, "xXXX")
|
||||
DECL(osl_sincos_dfdfdf, "xXXX")
|
||||
DECL(osl_sincos_vvv, "xXXX")
|
||||
DECL(osl_sincos_dvdvv, "xXXX")
|
||||
DECL(osl_sincos_dvvdv, "xXXX")
|
||||
DECL(osl_sincos_dvdvdv, "xXXX")
|
||||
|
||||
UNARY_OP_IMPL(log)
|
||||
UNARY_OP_IMPL(log2)
|
||||
@@ -253,138 +252,138 @@ BINARY_OP_IMPL(pow)
|
||||
UNARY_OP_IMPL(erf)
|
||||
UNARY_OP_IMPL(erfc)
|
||||
|
||||
DECL (osl_pow_vvf, "xXXf")
|
||||
DECL (osl_pow_dvdvdf, "xXXX")
|
||||
DECL (osl_pow_dvvdf, "xXXX")
|
||||
DECL (osl_pow_dvdvf, "xXXf")
|
||||
DECL(osl_pow_vvf, "xXXf")
|
||||
DECL(osl_pow_dvdvdf, "xXXX")
|
||||
DECL(osl_pow_dvvdf, "xXXX")
|
||||
DECL(osl_pow_dvdvf, "xXXf")
|
||||
|
||||
UNARY_OP_IMPL(sqrt)
|
||||
UNARY_OP_IMPL(inversesqrt)
|
||||
UNARY_OP_IMPL(cbrt)
|
||||
|
||||
DECL (osl_logb_ff, "ff")
|
||||
DECL (osl_logb_vv, "xXX")
|
||||
DECL(osl_logb_ff, "ff")
|
||||
DECL(osl_logb_vv, "xXX")
|
||||
|
||||
DECL (osl_floor_ff, "ff")
|
||||
DECL (osl_floor_vv, "xXX")
|
||||
DECL (osl_ceil_ff, "ff")
|
||||
DECL (osl_ceil_vv, "xXX")
|
||||
DECL (osl_round_ff, "ff")
|
||||
DECL (osl_round_vv, "xXX")
|
||||
DECL (osl_trunc_ff, "ff")
|
||||
DECL (osl_trunc_vv, "xXX")
|
||||
DECL (osl_sign_ff, "ff")
|
||||
DECL (osl_sign_vv, "xXX")
|
||||
DECL (osl_step_fff, "fff")
|
||||
DECL (osl_step_vvv, "xXXX")
|
||||
DECL(osl_floor_ff, "ff")
|
||||
DECL(osl_floor_vv, "xXX")
|
||||
DECL(osl_ceil_ff, "ff")
|
||||
DECL(osl_ceil_vv, "xXX")
|
||||
DECL(osl_round_ff, "ff")
|
||||
DECL(osl_round_vv, "xXX")
|
||||
DECL(osl_trunc_ff, "ff")
|
||||
DECL(osl_trunc_vv, "xXX")
|
||||
DECL(osl_sign_ff, "ff")
|
||||
DECL(osl_sign_vv, "xXX")
|
||||
DECL(osl_step_fff, "fff")
|
||||
DECL(osl_step_vvv, "xXXX")
|
||||
|
||||
DECL (osl_isnan_if, "if")
|
||||
DECL (osl_isinf_if, "if")
|
||||
DECL (osl_isfinite_if, "if")
|
||||
DECL (osl_abs_ii, "ii")
|
||||
DECL (osl_fabs_ii, "ii")
|
||||
DECL(osl_isnan_if, "if")
|
||||
DECL(osl_isinf_if, "if")
|
||||
DECL(osl_isfinite_if, "if")
|
||||
DECL(osl_abs_ii, "ii")
|
||||
DECL(osl_fabs_ii, "ii")
|
||||
|
||||
UNARY_OP_IMPL(abs)
|
||||
UNARY_OP_IMPL(fabs)
|
||||
BINARY_OP_IMPL(fmod)
|
||||
|
||||
DECL (osl_smoothstep_ffff, "ffff")
|
||||
DECL (osl_smoothstep_dfffdf, "xXffX")
|
||||
DECL (osl_smoothstep_dffdff, "xXfXf")
|
||||
DECL (osl_smoothstep_dffdfdf, "xXfXX")
|
||||
DECL (osl_smoothstep_dfdfff, "xXXff")
|
||||
DECL (osl_smoothstep_dfdffdf, "xXXfX")
|
||||
DECL (osl_smoothstep_dfdfdff, "xXXXf")
|
||||
DECL (osl_smoothstep_dfdfdfdf, "xXXXX")
|
||||
DECL(osl_smoothstep_ffff, "ffff")
|
||||
DECL(osl_smoothstep_dfffdf, "xXffX")
|
||||
DECL(osl_smoothstep_dffdff, "xXfXf")
|
||||
DECL(osl_smoothstep_dffdfdf, "xXfXX")
|
||||
DECL(osl_smoothstep_dfdfff, "xXXff")
|
||||
DECL(osl_smoothstep_dfdffdf, "xXXfX")
|
||||
DECL(osl_smoothstep_dfdfdff, "xXXXf")
|
||||
DECL(osl_smoothstep_dfdfdfdf, "xXXXX")
|
||||
|
||||
DECL (osl_dot_fvv, "fXX")
|
||||
DECL (osl_dot_dfdvdv, "xXXX")
|
||||
DECL (osl_dot_dfdvv, "xXXX")
|
||||
DECL (osl_dot_dfvdv, "xXXX")
|
||||
DECL (osl_cross_vvv, "xXXX")
|
||||
DECL (osl_cross_dvdvdv, "xXXX")
|
||||
DECL (osl_cross_dvdvv, "xXXX")
|
||||
DECL (osl_cross_dvvdv, "xXXX")
|
||||
DECL (osl_length_fv, "fX")
|
||||
DECL (osl_length_dfdv, "xXX")
|
||||
DECL (osl_distance_fvv, "fXX")
|
||||
DECL (osl_distance_dfdvdv, "xXXX")
|
||||
DECL (osl_distance_dfdvv, "xXXX")
|
||||
DECL (osl_distance_dfvdv, "xXXX")
|
||||
DECL (osl_normalize_vv, "xXX")
|
||||
DECL (osl_normalize_dvdv, "xXX")
|
||||
DECL(osl_dot_fvv, "fXX")
|
||||
DECL(osl_dot_dfdvdv, "xXXX")
|
||||
DECL(osl_dot_dfdvv, "xXXX")
|
||||
DECL(osl_dot_dfvdv, "xXXX")
|
||||
DECL(osl_cross_vvv, "xXXX")
|
||||
DECL(osl_cross_dvdvdv, "xXXX")
|
||||
DECL(osl_cross_dvdvv, "xXXX")
|
||||
DECL(osl_cross_dvvdv, "xXXX")
|
||||
DECL(osl_length_fv, "fX")
|
||||
DECL(osl_length_dfdv, "xXX")
|
||||
DECL(osl_distance_fvv, "fXX")
|
||||
DECL(osl_distance_dfdvdv, "xXXX")
|
||||
DECL(osl_distance_dfdvv, "xXXX")
|
||||
DECL(osl_distance_dfvdv, "xXXX")
|
||||
DECL(osl_normalize_vv, "xXX")
|
||||
DECL(osl_normalize_dvdv, "xXX")
|
||||
#endif
|
||||
|
||||
|
||||
DECL (osl_mul_mmm, "xXXX")
|
||||
DECL (osl_mul_mmf, "xXXf")
|
||||
DECL(osl_mul_mmm, "xXXX")
|
||||
DECL(osl_mul_mmf, "xXXf")
|
||||
|
||||
DECL (osl_div_mmm, "xXXX")
|
||||
DECL (osl_div_mmf, "xXXf")
|
||||
DECL (osl_div_mfm, "xXfX")
|
||||
DECL(osl_div_mmm, "xXXX")
|
||||
DECL(osl_div_mmf, "xXXf")
|
||||
DECL(osl_div_mfm, "xXfX")
|
||||
|
||||
DECL (osl_get_from_to_matrix, "iXXss")
|
||||
DECL (osl_transpose_mm, "xXX")
|
||||
DECL (osl_determinant_fm, "fX")
|
||||
DECL(osl_get_from_to_matrix, "iXXss")
|
||||
DECL(osl_transpose_mm, "xXX")
|
||||
DECL(osl_determinant_fm, "fX")
|
||||
|
||||
DECL (osl_concat_sss, "sss")
|
||||
DECL (osl_strlen_is, "is")
|
||||
DECL (osl_hash_is, "is")
|
||||
DECL (osl_getchar_isi, "isi");
|
||||
DECL (osl_startswith_iss, "iss")
|
||||
DECL (osl_endswith_iss, "iss")
|
||||
DECL (osl_stoi_is, "is")
|
||||
DECL (osl_stof_fs, "fs")
|
||||
DECL (osl_substr_ssii, "ssii")
|
||||
DECL (osl_regex_impl, "iXsXisi")
|
||||
DECL(osl_concat_sss, "sss")
|
||||
DECL(osl_strlen_is, "is")
|
||||
DECL(osl_hash_is, "is")
|
||||
DECL(osl_getchar_isi, "isi");
|
||||
DECL(osl_startswith_iss, "iss")
|
||||
DECL(osl_endswith_iss, "iss")
|
||||
DECL(osl_stoi_is, "is")
|
||||
DECL(osl_stof_fs, "fs")
|
||||
DECL(osl_substr_ssii, "ssii")
|
||||
DECL(osl_regex_impl, "iXsXisi")
|
||||
|
||||
// Used by wide code generator, but are uniform calls
|
||||
DECL (osl_texture_decode_wrapmode, "iX");
|
||||
DECL (osl_texture_decode_interpmode, "iX");
|
||||
DECL(osl_texture_decode_wrapmode, "iX");
|
||||
DECL(osl_texture_decode_interpmode, "iX");
|
||||
|
||||
DECL (osl_texture_set_firstchannel, "xXi")
|
||||
DECL (osl_texture_set_swrap, "xXs")
|
||||
DECL (osl_texture_set_twrap, "xXs")
|
||||
DECL (osl_texture_set_rwrap, "xXs")
|
||||
DECL (osl_texture_set_stwrap, "xXs")
|
||||
DECL (osl_texture_set_swrap_code, "xXi")
|
||||
DECL (osl_texture_set_twrap_code, "xXi")
|
||||
DECL (osl_texture_set_rwrap_code, "xXi")
|
||||
DECL (osl_texture_set_stwrap_code, "xXi")
|
||||
DECL (osl_texture_set_sblur, "xXf")
|
||||
DECL (osl_texture_set_tblur, "xXf")
|
||||
DECL (osl_texture_set_rblur, "xXf")
|
||||
DECL (osl_texture_set_stblur, "xXf")
|
||||
DECL (osl_texture_set_swidth, "xXf")
|
||||
DECL (osl_texture_set_twidth, "xXf")
|
||||
DECL (osl_texture_set_rwidth, "xXf")
|
||||
DECL (osl_texture_set_stwidth, "xXf")
|
||||
DECL (osl_texture_set_fill, "xXf")
|
||||
DECL (osl_texture_set_time, "xXf")
|
||||
DECL (osl_texture_set_interp, "xXs")
|
||||
DECL (osl_texture_set_interp_code, "xXi")
|
||||
DECL (osl_texture_set_subimage, "xXi")
|
||||
DECL (osl_texture_set_subimagename, "xXs")
|
||||
DECL (osl_texture_set_missingcolor_arena, "xXX")
|
||||
DECL (osl_texture_set_missingcolor_alpha, "xXif")
|
||||
DECL (osl_texture, "iXXXXffffffiXXXXXXX")
|
||||
DECL (osl_texture3d, "iXXXXXXXXiXXXXXXX")
|
||||
DECL (osl_environment, "iXXXXXXXiXXXXXXX")
|
||||
DECL (osl_get_textureinfo, "iXXXXiiiXX")
|
||||
DECL (osl_get_textureinfo_st, "iXXXffXiiiXX")
|
||||
DECL(osl_texture_set_firstchannel, "xXi")
|
||||
DECL(osl_texture_set_swrap, "xXs")
|
||||
DECL(osl_texture_set_twrap, "xXs")
|
||||
DECL(osl_texture_set_rwrap, "xXs")
|
||||
DECL(osl_texture_set_stwrap, "xXs")
|
||||
DECL(osl_texture_set_swrap_code, "xXi")
|
||||
DECL(osl_texture_set_twrap_code, "xXi")
|
||||
DECL(osl_texture_set_rwrap_code, "xXi")
|
||||
DECL(osl_texture_set_stwrap_code, "xXi")
|
||||
DECL(osl_texture_set_sblur, "xXf")
|
||||
DECL(osl_texture_set_tblur, "xXf")
|
||||
DECL(osl_texture_set_rblur, "xXf")
|
||||
DECL(osl_texture_set_stblur, "xXf")
|
||||
DECL(osl_texture_set_swidth, "xXf")
|
||||
DECL(osl_texture_set_twidth, "xXf")
|
||||
DECL(osl_texture_set_rwidth, "xXf")
|
||||
DECL(osl_texture_set_stwidth, "xXf")
|
||||
DECL(osl_texture_set_fill, "xXf")
|
||||
DECL(osl_texture_set_time, "xXf")
|
||||
DECL(osl_texture_set_interp, "xXs")
|
||||
DECL(osl_texture_set_interp_code, "xXi")
|
||||
DECL(osl_texture_set_subimage, "xXi")
|
||||
DECL(osl_texture_set_subimagename, "xXs")
|
||||
DECL(osl_texture_set_missingcolor_arena, "xXX")
|
||||
DECL(osl_texture_set_missingcolor_alpha, "xXif")
|
||||
DECL(osl_texture, "iXXXXffffffiXXXXXXX")
|
||||
DECL(osl_texture3d, "iXXXXXXXXiXXXXXXX")
|
||||
DECL(osl_environment, "iXXXXXXXiXXXXXXX")
|
||||
DECL(osl_get_textureinfo, "iXXXXiiiXX")
|
||||
DECL(osl_get_textureinfo_st, "iXXXffXiiiXX")
|
||||
|
||||
DECL (osl_trace_set_mindist, "xXf")
|
||||
DECL (osl_trace_set_maxdist, "xXf")
|
||||
DECL (osl_trace_set_shade, "xXi")
|
||||
DECL (osl_trace_set_traceset, "xXs")
|
||||
DECL (osl_trace, "iXXXXXXXX")
|
||||
DECL(osl_trace_set_mindist, "xXf")
|
||||
DECL(osl_trace_set_maxdist, "xXf")
|
||||
DECL(osl_trace_set_shade, "xXi")
|
||||
DECL(osl_trace_set_traceset, "xXs")
|
||||
DECL(osl_trace, "iXXXXXXXX")
|
||||
|
||||
#ifdef OSL_LLVM_NO_BITCODE
|
||||
DECL (osl_calculatenormal, "xXXX")
|
||||
DECL (osl_area, "fX")
|
||||
DECL (osl_filterwidth_fdf, "fX")
|
||||
DECL (osl_filterwidth_vdv, "xXX")
|
||||
DECL (osl_raytype_bit, "iXi")
|
||||
DECL(osl_calculatenormal, "xXXX")
|
||||
DECL(osl_area, "fX")
|
||||
DECL(osl_filterwidth_fdf, "fX")
|
||||
DECL(osl_filterwidth_vdv, "xXX")
|
||||
DECL(osl_raytype_bit, "iXi")
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -143,15 +143,15 @@
|
||||
DECL(__OSL_MASKED_OP3(name, Wdv, Wv, Wdv), "xXXXi") \
|
||||
DECL(__OSL_MASKED_OP3(name, Wdv, Wdv, Wv), "xXXXi")
|
||||
|
||||
#define WIDE_BINARY_OP_IMPL(name) \
|
||||
DECL(__OSL_OP3(name, Wf, Wf, Wf), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdf, Wdf, Wdf), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdf, Wf, Wdf), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdf, Wdf, Wf), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wv, Wv, Wv), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdv, Wdv, Wdv), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdv, Wv, Wdv), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdv, Wdv, Wv), "xXXX") \
|
||||
#define WIDE_BINARY_OP_IMPL(name) \
|
||||
DECL(__OSL_OP3(name, Wf, Wf, Wf), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdf, Wdf, Wdf), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdf, Wf, Wdf), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdf, Wdf, Wf), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wv, Wv, Wv), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdv, Wdv, Wdv), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdv, Wv, Wdv), "xXXX") \
|
||||
DECL(__OSL_OP3(name, Wdv, Wdv, Wv), "xXXX") \
|
||||
WIDE_BINARY_OP_MASKED_IMPL(name)
|
||||
|
||||
|
||||
@@ -168,14 +168,12 @@
|
||||
DECL(__OSL_OP3(name, Wv, Wv, Wv), "xXXX") \
|
||||
DECL(__OSL_MASKED_OP3(name, Wv, Wv, Wv), "xXXXi")
|
||||
|
||||
#if 0 // incomplete closure support
|
||||
DECL (osl_add_closure_closure, "CXCC")
|
||||
DECL (osl_mul_closure_float, "CXCf")
|
||||
DECL (osl_mul_closure_color, "CXCc")
|
||||
DECL (osl_allocate_closure_component, "CXii")
|
||||
DECL (osl_allocate_weighted_closure_component, "CXiiX")
|
||||
DECL (osl_closure_to_string, "sXC")
|
||||
#endif
|
||||
DECL(__OSL_MASKED_OP(allocate_closure_component), "xXXiii")
|
||||
DECL(__OSL_MASKED_OP(allocate_weighted_closure_component), "xXXiiXi")
|
||||
DECL(__OSL_MASKED_OP(add_closure_closure), "xXXXXi")
|
||||
DECL(__OSL_MASKED_OP(mul_closure_float), "xXXXXi")
|
||||
DECL(__OSL_MASKED_OP(mul_closure_color), "xXXXXi")
|
||||
DECL(__OSL_OP(closure_to_string), "sXX")
|
||||
|
||||
DECL(__OSL_OP(format), "xXis*")
|
||||
DECL(__OSL_OP(printf), "xXis*")
|
||||
@@ -243,19 +241,19 @@ WIDE_NOISE_DERIV_IMPL(unullnoise)
|
||||
|
||||
DECL(__OSL_MASKED_OP(count_noise), "xXi")
|
||||
|
||||
DECL (__OSL_OP2(hash,Wi,Wi), "xXX")
|
||||
DECL (__OSL_OP2(hash,Wi,Wf), "xXX")
|
||||
DECL (__OSL_OP3(hash,Wi,Wf,Wf), "xXXX")
|
||||
DECL (__OSL_OP2(hash,Wi,Wv), "xXX")
|
||||
DECL (__OSL_OP3(hash,Wi,Wv,Wf), "xXXX")
|
||||
DECL (__OSL_MASKED_OP2(hash,Wi,Wi), "xXXi")
|
||||
DECL (__OSL_MASKED_OP2(hash,Wi,Wf), "xXXi")
|
||||
DECL (__OSL_MASKED_OP3(hash,Wi,Wf,Wf), "xXXXi")
|
||||
DECL (__OSL_MASKED_OP2(hash,Wi,Wv), "xXXi")
|
||||
DECL (__OSL_MASKED_OP3(hash,Wi,Wv,Wf), "xXXXi")
|
||||
DECL(__OSL_OP2(hash, Wi, Wi), "xXX")
|
||||
DECL(__OSL_OP2(hash, Wi, Wf), "xXX")
|
||||
DECL(__OSL_OP3(hash, Wi, Wf, Wf), "xXXX")
|
||||
DECL(__OSL_OP2(hash, Wi, Wv), "xXX")
|
||||
DECL(__OSL_OP3(hash, Wi, Wv, Wf), "xXXX")
|
||||
DECL(__OSL_MASKED_OP2(hash, Wi, Wi), "xXXi")
|
||||
DECL(__OSL_MASKED_OP2(hash, Wi, Wf), "xXXi")
|
||||
DECL(__OSL_MASKED_OP3(hash, Wi, Wf, Wf), "xXXXi")
|
||||
DECL(__OSL_MASKED_OP2(hash, Wi, Wv), "xXXi")
|
||||
DECL(__OSL_MASKED_OP3(hash, Wi, Wv, Wf), "xXXXi")
|
||||
|
||||
// Need wide for combinations of the 3 parameters allowed to be uniform
|
||||
// caveat, some combos are unreachable/uneeded
|
||||
// caveat, some combos are unreachable/unneeded
|
||||
// When result has a derivative, there is
|
||||
// no "easy" have a input parameter be non-derivative based on code
|
||||
// analysis promoting all inputs to be derivative base.
|
||||
@@ -317,7 +315,7 @@ DECL(__OSL_MASKED_OP(pointcloud_get), "iXsXiXsLXi")
|
||||
DECL(__OSL_MASKED_OP(pointcloud_write), "iXsXiXXXi")
|
||||
|
||||
DECL(__OSL_MASKED_OP(getmessage), "xXXssLXiisii")
|
||||
DECL(__OSL_MASKED_OP2(setmessage, s, WX), "xXXLXisii")
|
||||
DECL(__OSL_MASKED_OP2(setmessage, s, WX), "xXXLXisii")
|
||||
DECL(__OSL_MASKED_OP2(setmessage, Ws, WX), "xXXLXisii")
|
||||
|
||||
DECL(__OSL_OP(blackbody_vf), "xXXf")
|
||||
@@ -383,7 +381,7 @@ DECL(__OSL_OP(get_attribute_uniform), "iXiXXiiXX")
|
||||
// TODO: shouldn't bind_interpolated_param be MASKED? change name to reflect
|
||||
DECL(__OSL_OP(bind_interpolated_param), "iXXLiXiXiXii")
|
||||
|
||||
//DECL (osl_get_texture_options, "XX") // uneeded
|
||||
//DECL (osl_get_texture_options, "XX") // unneeded
|
||||
DECL(__OSL_OP(get_noise_options), "XX")
|
||||
|
||||
// The following are defined inside llvm_ops.cpp. Only include these
|
||||
|
||||
+49
-37
@@ -2,15 +2,16 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <OpenImageIO/sysutil.h>
|
||||
|
||||
#include <OSL/oslconfig.h>
|
||||
#include <OSL/oslclosure.h>
|
||||
#include <OSL/genclosure.h>
|
||||
#include <OSL/oslclosure.h>
|
||||
#include <OSL/oslconfig.h>
|
||||
|
||||
#include "oslexec_pvt.h"
|
||||
|
||||
|
||||
@@ -38,46 +39,54 @@ namespace pvt {
|
||||
|
||||
|
||||
static void
|
||||
print_component_value(std::ostream &out, ShadingSystemImpl *ss,
|
||||
TypeDesc type, const void *data)
|
||||
print_component_value(std::ostream& out, ShadingSystemImpl* ss, TypeDesc type,
|
||||
const void* data)
|
||||
|
||||
{
|
||||
if (type == TypeDesc::TypeInt)
|
||||
out << *(int *)data;
|
||||
out << *(int*)data;
|
||||
else if (type == TypeDesc::TypeFloat)
|
||||
out << *(float *)data;
|
||||
out << *(float*)data;
|
||||
else if (type == TypeDesc::TypeColor)
|
||||
out << "(" << ((Color3 *)data)->x << ", " << ((Color3 *)data)->y << ", " << ((Color3 *)data)->z << ")";
|
||||
out << "(" << ((Color3*)data)->x << ", " << ((Color3*)data)->y << ", "
|
||||
<< ((Color3*)data)->z << ")";
|
||||
else if (type == TypeDesc::TypeVector)
|
||||
out << "(" << ((Vec3 *)data)->x << ", " << ((Vec3 *)data)->y << ", " << ((Vec3 *)data)->z << ")";
|
||||
out << "(" << ((Vec3*)data)->x << ", " << ((Vec3*)data)->y << ", "
|
||||
<< ((Vec3*)data)->z << ")";
|
||||
else if (type == TypeDesc::TypeString)
|
||||
out << "\"" << *((ustring *)data) << "\"";
|
||||
out << "\"" << *((ustring*)data) << "\"";
|
||||
else if (type == TypeDesc::PTR) // this only happens for closures
|
||||
print_closure (out, *(const ClosureColor **)data, ss);
|
||||
print_closure(out, *(const ClosureColor**)data, ss);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
print_component (std::ostream &out, const ClosureComponent *comp, ShadingSystemImpl *ss, const Color3 &weight)
|
||||
print_component(std::ostream& out, const ClosureComponent* comp,
|
||||
ShadingSystemImpl* ss, const Color3& weight)
|
||||
{
|
||||
const ClosureRegistry::ClosureEntry *clentry = ss->find_closure(comp->id);
|
||||
const ClosureRegistry::ClosureEntry* clentry = ss->find_closure(comp->id);
|
||||
OSL_ASSERT(clentry);
|
||||
out << "(" << weight.x*comp->w.x << ", " << weight.y*comp->w.y << ", " << weight.z*comp->w.z << ") * ";
|
||||
out << "(" << weight.x * comp->w.x << ", " << weight.y * comp->w.y << ", "
|
||||
<< weight.z * comp->w.z << ") * ";
|
||||
out << clentry->name.c_str() << " (";
|
||||
for (int i = 0, nparams = clentry->params.size() - 1; i < nparams; ++i) {
|
||||
if (i) out << ", ";
|
||||
if (i)
|
||||
out << ", ";
|
||||
const ClosureParam& param = clentry->params[i];
|
||||
if (param.key != 0)
|
||||
out << "\"" << param.key << "\", ";
|
||||
if (param.type.numelements() > 1) out << "[";
|
||||
if (param.type.numelements() > 1)
|
||||
out << "[";
|
||||
for (size_t j = 0; j < param.type.numelements(); ++j) {
|
||||
if (j) out << ", ";
|
||||
if (j)
|
||||
out << ", ";
|
||||
print_component_value(out, ss, param.type.elementtype(),
|
||||
(const char *)comp->data() + param.offset
|
||||
+ param.type.elementsize() * j);
|
||||
(const char*)comp->data() + param.offset
|
||||
+ param.type.elementsize() * j);
|
||||
}
|
||||
if (clentry->params[i].type.numelements() > 1) out << "]";
|
||||
if (clentry->params[i].type.numelements() > 1)
|
||||
out << "]";
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
@@ -85,32 +94,35 @@ print_component (std::ostream &out, const ClosureComponent *comp, ShadingSystemI
|
||||
|
||||
|
||||
static void
|
||||
print_closure (std::ostream &out, const ClosureColor *closure, ShadingSystemImpl *ss, const Color3 &w, bool &first)
|
||||
print_closure(std::ostream& out, const ClosureColor* closure,
|
||||
ShadingSystemImpl* ss, const Color3& w, bool& first)
|
||||
{
|
||||
if (closure == NULL)
|
||||
return;
|
||||
|
||||
switch (closure->id) {
|
||||
case ClosureColor::MUL:
|
||||
print_closure(out, closure->as_mul()->closure, ss, closure->as_mul()->weight * w, first);
|
||||
break;
|
||||
case ClosureColor::ADD:
|
||||
print_closure(out, closure->as_add()->closureA, ss, w, first);
|
||||
print_closure(out, closure->as_add()->closureB, ss, w, first);
|
||||
break;
|
||||
default:
|
||||
if (!first)
|
||||
out << "\n\t+ ";
|
||||
print_component (out, closure->as_comp(), ss, w);
|
||||
first = false;
|
||||
break;
|
||||
case ClosureColor::MUL:
|
||||
print_closure(out, closure->as_mul()->closure, ss,
|
||||
closure->as_mul()->weight * w, first);
|
||||
break;
|
||||
case ClosureColor::ADD:
|
||||
print_closure(out, closure->as_add()->closureA, ss, w, first);
|
||||
print_closure(out, closure->as_add()->closureB, ss, w, first);
|
||||
break;
|
||||
default:
|
||||
if (!first)
|
||||
out << "\n\t+ ";
|
||||
print_component(out, closure->as_comp(), ss, w);
|
||||
first = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
print_closure (std::ostream &out, const ClosureColor *closure, ShadingSystemImpl *ss)
|
||||
print_closure(std::ostream& out, const ClosureColor* closure,
|
||||
ShadingSystemImpl* ss)
|
||||
{
|
||||
bool first = true;
|
||||
print_closure(out, closure, ss, Color3(1, 1, 1), first);
|
||||
@@ -118,7 +130,7 @@ print_closure (std::ostream &out, const ClosureColor *closure, ShadingSystemImpl
|
||||
|
||||
|
||||
|
||||
} // namespace pvt
|
||||
} // namespace pvt
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <OpenImageIO/thread.h>
|
||||
|
||||
@@ -27,48 +27,48 @@ namespace pvt {
|
||||
/// a new allocation tries to fit it in one of the allocated blocks, but
|
||||
/// if it won't fit anywhere, it makes a new block and adds it to the
|
||||
/// head of the list.
|
||||
template<class T>
|
||||
class ConstantPool {
|
||||
template<class T> class ConstantPool {
|
||||
public:
|
||||
/// Allocate a new pool of T's. The quanta, if supplied, is the
|
||||
/// number of T's to malloc at a time.
|
||||
ConstantPool (size_t quanta = 1000000) : m_quanta(quanta), m_total(0) { }
|
||||
ConstantPool(size_t quanta = 1000000) : m_quanta(quanta), m_total(0) {}
|
||||
|
||||
~ConstantPool () { }
|
||||
~ConstantPool() {}
|
||||
|
||||
/// Allocate space enough for n T's, and return a pointer to the
|
||||
/// start of that space.
|
||||
T * alloc (size_t n) {
|
||||
OIIO::lock_guard lock (m_mutex);
|
||||
T* alloc(size_t n)
|
||||
{
|
||||
OIIO::lock_guard lock(m_mutex);
|
||||
// Check each block in the block list to see if it has enough space
|
||||
for (auto&& block : m_block_list) {
|
||||
size_t s = block.size();
|
||||
if ((s+n) <= block.capacity()) {
|
||||
if ((s + n) <= block.capacity()) {
|
||||
// Enough space in this block. Use it.
|
||||
block.resize (s+n);
|
||||
block.resize(s + n);
|
||||
return &block[s];
|
||||
}
|
||||
}
|
||||
// If we got here, there were no mini-blocks in the list with enough
|
||||
// space. Make a new one.
|
||||
m_block_list.push_front (block_t());
|
||||
block_t &block (m_block_list.front());
|
||||
size_t s = std::max (m_quanta, n);
|
||||
block.reserve (s);
|
||||
m_block_list.push_front(block_t());
|
||||
block_t& block(m_block_list.front());
|
||||
size_t s = std::max(m_quanta, n);
|
||||
block.reserve(s);
|
||||
m_total += s * sizeof(T);
|
||||
block.resize (n);
|
||||
block.resize(n);
|
||||
return &block[0];
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::vector<T> block_t; ///< Type of block
|
||||
std::list<block_t> m_block_list; ///< List of memory blocks
|
||||
size_t m_quanta; ///< How big each memory block is (in T's, not bytes)
|
||||
size_t m_total; ///< Total memory allocated (bytes!)
|
||||
size_t m_quanta; ///< How big each memory block is (in T's, not bytes)
|
||||
size_t m_total; ///< Total memory allocated (bytes!)
|
||||
OIIO::mutex m_mutex; ///< Thread-safe lock
|
||||
};
|
||||
|
||||
|
||||
|
||||
}; // namespace OSL::pvt
|
||||
}; // namespace pvt
|
||||
OSL_NAMESPACE_EXIT
|
||||
|
||||
+1206
-1133
File diff suppressed because it is too large
Load Diff
+210
-195
@@ -2,19 +2,19 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <OpenImageIO/sysutil.h>
|
||||
#include <OpenImageIO/timer.h>
|
||||
#include <OpenImageIO/thread.h>
|
||||
#include <OpenImageIO/timer.h>
|
||||
|
||||
#include <OSL/oslconfig.h>
|
||||
|
||||
#if OSL_USE_BATCHED
|
||||
#include <OSL/batched_shaderglobals.h>
|
||||
# include <OSL/batched_shaderglobals.h>
|
||||
#endif
|
||||
|
||||
#include <OSL/mask.h>
|
||||
@@ -32,36 +32,40 @@ static mutex buffered_file_output_mutex;
|
||||
|
||||
namespace pvt {
|
||||
|
||||
template <size_t ByteAlignmentT, typename T>
|
||||
inline bool is_aligned(const T *pointer)
|
||||
template<size_t ByteAlignmentT, typename T>
|
||||
inline bool
|
||||
is_aligned(const T* pointer)
|
||||
{
|
||||
std::uintptr_t ptrAsUint = reinterpret_cast<std::uintptr_t>(pointer);
|
||||
return (ptrAsUint%ByteAlignmentT==0);
|
||||
return (ptrAsUint % ByteAlignmentT == 0);
|
||||
}
|
||||
|
||||
} // namespace pvt
|
||||
} // namespace pvt
|
||||
|
||||
ShadingContext::ShadingContext (ShadingSystemImpl &shadingsys,
|
||||
PerThreadInfo *threadinfo)
|
||||
: m_shadingsys(shadingsys), m_renderer(m_shadingsys.renderer()),
|
||||
m_group(NULL), m_max_warnings(shadingsys.max_warnings_per_thread()),
|
||||
m_dictionary(NULL), batch_size_executed(0)
|
||||
ShadingContext::ShadingContext(ShadingSystemImpl& shadingsys,
|
||||
PerThreadInfo* threadinfo)
|
||||
: m_shadingsys(shadingsys)
|
||||
, m_renderer(m_shadingsys.renderer())
|
||||
, m_group(NULL)
|
||||
, m_max_warnings(shadingsys.max_warnings_per_thread())
|
||||
, m_dictionary(NULL)
|
||||
, batch_size_executed(0)
|
||||
{
|
||||
m_shadingsys.m_stat_contexts += 1;
|
||||
m_threadinfo = threadinfo ? threadinfo : shadingsys.get_perthread_info ();
|
||||
m_threadinfo = threadinfo ? threadinfo : shadingsys.get_perthread_info();
|
||||
m_texture_thread_info = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ShadingContext::~ShadingContext ()
|
||||
ShadingContext::~ShadingContext()
|
||||
{
|
||||
process_errors ();
|
||||
process_errors();
|
||||
#if OSL_USE_BATCHED
|
||||
process_file_output();
|
||||
#endif
|
||||
m_shadingsys.m_stat_contexts -= 1;
|
||||
free_dict_resources ();
|
||||
free_dict_resources();
|
||||
}
|
||||
|
||||
|
||||
@@ -72,61 +76,64 @@ ShadingContext::execute_init(ShaderGroup& sgroup, int shadeindex,
|
||||
void* output_base_ptr, bool run)
|
||||
{
|
||||
if (m_group)
|
||||
execute_cleanup ();
|
||||
execute_cleanup();
|
||||
batch_size_executed = 0;
|
||||
m_group = &sgroup;
|
||||
m_ticks = 0;
|
||||
m_group = &sgroup;
|
||||
m_ticks = 0;
|
||||
|
||||
// Optimize if we haven't already
|
||||
if (sgroup.nlayers()) {
|
||||
sgroup.start_running ();
|
||||
if (! sgroup.jitted()) {
|
||||
sgroup.start_running();
|
||||
if (!sgroup.jitted()) {
|
||||
auto ctx = shadingsys().get_context(thread_info());
|
||||
shadingsys().optimize_group (sgroup, ctx, true /*do_jit*/);
|
||||
if (shadingsys().m_greedyjit && shadingsys().m_groups_to_compile_count) {
|
||||
shadingsys().optimize_group(sgroup, ctx, true /*do_jit*/);
|
||||
if (shadingsys().m_greedyjit
|
||||
&& shadingsys().m_groups_to_compile_count) {
|
||||
// If we are greedily JITing, optimize/JIT everything now
|
||||
shadingsys().optimize_all_groups ();
|
||||
shadingsys().optimize_all_groups();
|
||||
}
|
||||
shadingsys().release_context(ctx);
|
||||
}
|
||||
if (sgroup.does_nothing())
|
||||
return false;
|
||||
} else {
|
||||
// empty shader - nothing to do!
|
||||
return false;
|
||||
// empty shader - nothing to do!
|
||||
return false;
|
||||
}
|
||||
|
||||
int profile = shadingsys().m_profile;
|
||||
OIIO::Timer timer (profile ? OIIO::Timer::StartNow : OIIO::Timer::DontStartNow);
|
||||
OIIO::Timer timer(profile ? OIIO::Timer::StartNow
|
||||
: OIIO::Timer::DontStartNow);
|
||||
|
||||
// Allocate enough space on the heap
|
||||
size_t heap_size_needed = sgroup.llvm_groupdata_size();
|
||||
reserve_heap(heap_size_needed);
|
||||
// Zero out the heap memory we will be using
|
||||
if (shadingsys().m_clearmemory)
|
||||
memset (m_heap.get(), 0, heap_size_needed);
|
||||
memset(m_heap.get(), 0, heap_size_needed);
|
||||
|
||||
// Set up closure storage
|
||||
m_closure_pool.clear();
|
||||
|
||||
// Clear the message blackboard
|
||||
m_messages.clear ();
|
||||
m_messages.clear();
|
||||
|
||||
// Clear miscellaneous scratch space
|
||||
m_scratch_pool.clear ();
|
||||
m_scratch_pool.clear();
|
||||
|
||||
// Zero out stats for this execution
|
||||
clear_runtime_stats ();
|
||||
clear_runtime_stats();
|
||||
|
||||
if (run) {
|
||||
RunLLVMGroupFunc run_func = sgroup.llvm_compiled_init();
|
||||
if (!run_func)
|
||||
return false;
|
||||
ssg.context = this;
|
||||
ssg.renderer = renderer();
|
||||
ssg.Ci = NULL;
|
||||
run_func (&ssg, m_heap.get(), userdata_base_ptr, output_base_ptr,
|
||||
shadeindex);
|
||||
ssg.context = this;
|
||||
ssg.shadingStateUniform = &(shadingsys().m_shading_state_uniform);
|
||||
ssg.renderer = renderer();
|
||||
ssg.Ci = NULL;
|
||||
run_func(&ssg, m_heap.get(), userdata_base_ptr, output_base_ptr,
|
||||
shadeindex);
|
||||
}
|
||||
|
||||
if (profile)
|
||||
@@ -146,14 +153,15 @@ ShadingContext::execute_layer(int shadeindex, ShaderGlobals& ssg,
|
||||
OSL_DASSERT(ssg.context == this && ssg.renderer == renderer());
|
||||
|
||||
int profile = shadingsys().m_profile;
|
||||
OIIO::Timer timer (profile ? OIIO::Timer::StartNow : OIIO::Timer::DontStartNow);
|
||||
OIIO::Timer timer(profile ? OIIO::Timer::StartNow
|
||||
: OIIO::Timer::DontStartNow);
|
||||
|
||||
RunLLVMGroupFunc run_func = group()->llvm_compiled_layer (layernumber);
|
||||
if (! run_func)
|
||||
RunLLVMGroupFunc run_func = group()->llvm_compiled_layer(layernumber);
|
||||
if (!run_func)
|
||||
return false;
|
||||
|
||||
run_func (&ssg, m_heap.get(), userdata_base_ptr, output_base_ptr,
|
||||
shadeindex);
|
||||
run_func(&ssg, m_heap.get(), userdata_base_ptr, output_base_ptr,
|
||||
shadeindex);
|
||||
|
||||
if (profile)
|
||||
m_ticks += timer.ticks();
|
||||
@@ -164,21 +172,21 @@ ShadingContext::execute_layer(int shadeindex, ShaderGlobals& ssg,
|
||||
|
||||
|
||||
bool
|
||||
ShadingContext::execute_cleanup ()
|
||||
ShadingContext::execute_cleanup()
|
||||
{
|
||||
if (! group()) {
|
||||
errorf("execute_cleanup called again on a cleaned-up context");
|
||||
if (!group()) {
|
||||
errorfmt("execute_cleanup called again on a cleaned-up context");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Process any queued up error messages, warnings, printfs from shaders
|
||||
process_errors ();
|
||||
process_errors();
|
||||
#if OSL_USE_BATCHED
|
||||
process_file_output();
|
||||
#endif
|
||||
|
||||
if (shadingsys().m_profile) {
|
||||
record_runtime_stats (); // Transfer runtime stats to the shadingsys
|
||||
record_runtime_stats(); // Transfer runtime stats to the shadingsys
|
||||
shadingsys().m_stat_total_shading_time_ticks += m_ticks;
|
||||
group()->m_stat_total_shading_time_ticks += m_ticks;
|
||||
}
|
||||
@@ -189,38 +197,38 @@ ShadingContext::execute_cleanup ()
|
||||
|
||||
|
||||
bool
|
||||
ShadingContext::execute (ShaderGroup &sgroup, int shadeindex,
|
||||
ShaderGlobals &ssg, void* userdata_base_ptr,
|
||||
void* output_base_ptr, bool run)
|
||||
ShadingContext::execute(ShaderGroup& sgroup, int shadeindex, ShaderGlobals& ssg,
|
||||
void* userdata_base_ptr, void* output_base_ptr,
|
||||
bool run)
|
||||
{
|
||||
int n = sgroup.m_exec_repeat;
|
||||
Vec3 Psave, Nsave; // for repeats
|
||||
Vec3 Psave, Nsave; // for repeats
|
||||
bool repeat = (n > 1);
|
||||
if (repeat) {
|
||||
// If we're going to repeat more than once, we need to save any
|
||||
// globals that might get modified.
|
||||
Psave = ssg.P;
|
||||
Nsave = ssg.N;
|
||||
if (! run)
|
||||
if (!run)
|
||||
n = 1;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
while (1) {
|
||||
if (! execute_init (sgroup, shadeindex, ssg, userdata_base_ptr,
|
||||
output_base_ptr, run))
|
||||
if (!execute_init(sgroup, shadeindex, ssg, userdata_base_ptr,
|
||||
output_base_ptr, run))
|
||||
return false;
|
||||
if (run && n)
|
||||
execute_layer (shadeindex, ssg, userdata_base_ptr, output_base_ptr,
|
||||
group()->nlayers() - 1);
|
||||
result = execute_cleanup ();
|
||||
execute_layer(shadeindex, ssg, userdata_base_ptr, output_base_ptr,
|
||||
group()->nlayers() - 1);
|
||||
result = execute_cleanup();
|
||||
if (--n < 1)
|
||||
break; // done
|
||||
break; // done
|
||||
if (repeat) {
|
||||
// Going around for another pass... restore things as best as we
|
||||
// can.
|
||||
ssg.P = Psave;
|
||||
ssg.N = Nsave;
|
||||
ssg.P = Psave;
|
||||
ssg.N = Nsave;
|
||||
ssg.Ci = NULL;
|
||||
}
|
||||
}
|
||||
@@ -232,24 +240,22 @@ ShadingContext::execute (ShaderGroup &sgroup, int shadeindex,
|
||||
|
||||
template<int WidthT>
|
||||
bool
|
||||
ShadingContext::Batched<WidthT>::execute_init( ShaderGroup &sgroup,
|
||||
int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT> &bsg,
|
||||
void* userdata_base_ptr,
|
||||
void* output_base_ptr, bool run)
|
||||
ShadingContext::Batched<WidthT>::execute_init(
|
||||
ShaderGroup& sgroup, int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex, BatchedShaderGlobals<WidthT>& bsg,
|
||||
void* userdata_base_ptr, void* output_base_ptr, bool run)
|
||||
{
|
||||
if (context().m_group)
|
||||
context().execute_cleanup ();
|
||||
context().execute_cleanup();
|
||||
|
||||
context().batch_size_executed = batch_size;
|
||||
context().m_group = &sgroup;
|
||||
context().m_ticks = 0;
|
||||
context().m_group = &sgroup;
|
||||
context().m_ticks = 0;
|
||||
|
||||
// Optimize if we haven't already
|
||||
if (sgroup.nlayers()) {
|
||||
sgroup.start_running ();
|
||||
if (! sgroup.batch_jitted()) {
|
||||
sgroup.start_running();
|
||||
if (!sgroup.batch_jitted()) {
|
||||
// Matching ShadingContext::execute_init behavior
|
||||
// of grabbing another context.
|
||||
// TODO: Is this necessary, why can't we just use the
|
||||
@@ -257,7 +263,8 @@ ShadingContext::Batched<WidthT>::execute_init( ShaderGroup &sgroup,
|
||||
//shadingsys().template batched<WidthT>().jit_group(sgroup, &context());
|
||||
auto ctx = shadingsys().get_context(context().thread_info());
|
||||
shadingsys().template batched<WidthT>().jit_group(sgroup, ctx);
|
||||
if (shadingsys().m_greedyjit && shadingsys().m_groups_to_compile_count) {
|
||||
if (shadingsys().m_greedyjit
|
||||
&& shadingsys().m_groups_to_compile_count) {
|
||||
// If we are greedily JITing, optimize/JIT everything now
|
||||
shadingsys().template batched<WidthT>().jit_all_groups();
|
||||
}
|
||||
@@ -273,47 +280,48 @@ ShadingContext::Batched<WidthT>::execute_init( ShaderGroup &sgroup,
|
||||
// default value ourselves
|
||||
|
||||
} else {
|
||||
// empty shader - nothing to do!
|
||||
return false;
|
||||
// empty shader - nothing to do!
|
||||
return false;
|
||||
}
|
||||
|
||||
int profile = shadingsys().m_profile;
|
||||
OIIO::Timer timer (profile ? OIIO::Timer::StartNow : OIIO::Timer::DontStartNow);
|
||||
OIIO::Timer timer(profile ? OIIO::Timer::StartNow
|
||||
: OIIO::Timer::DontStartNow);
|
||||
|
||||
// Allocate enough space on the heap
|
||||
size_t heap_size_needed = sgroup.llvm_groupdata_wide_size();
|
||||
context().reserve_heap(heap_size_needed);
|
||||
// Zero out the heap memory we will be using
|
||||
if (shadingsys().m_clearmemory)
|
||||
memset (context().m_heap.get(), 0, heap_size_needed);
|
||||
memset(context().m_heap.get(), 0, heap_size_needed);
|
||||
|
||||
// Set up closure storage
|
||||
context().m_closure_pool.clear();
|
||||
|
||||
// Clear the message blackboard
|
||||
context().m_messages.clear ();
|
||||
context().batched_messages_buffer().clear ();
|
||||
context().m_messages.clear();
|
||||
context().batched_messages_buffer().clear();
|
||||
|
||||
// Clear miscellaneous scratch space
|
||||
context().m_scratch_pool.clear ();
|
||||
context().m_scratch_pool.clear();
|
||||
|
||||
// Zero out stats for this execution
|
||||
context().clear_runtime_stats ();
|
||||
context().clear_runtime_stats();
|
||||
|
||||
if (run) {
|
||||
bsg.uniform.context = &context();
|
||||
bsg.uniform.context = &context();
|
||||
bsg.uniform.renderer = context().renderer();
|
||||
bsg.uniform.Ci = NULL;
|
||||
assign_all(bsg.varying.Ci, (ClosureColor*)nullptr);
|
||||
RunLLVMGroupFuncWide run_func = sgroup.llvm_compiled_wide_init();
|
||||
OSL_DASSERT (run_func);
|
||||
OSL_DASSERT (sgroup.llvm_groupdata_wide_size() <= context().m_heapsize);
|
||||
OSL_DASSERT(run_func);
|
||||
OSL_DASSERT(sgroup.llvm_groupdata_wide_size() <= context().m_heapsize);
|
||||
|
||||
if(batch_size > 0) {
|
||||
if (batch_size > 0) {
|
||||
Mask<WidthT> run_mask(false);
|
||||
run_mask.set_count_on(batch_size);
|
||||
|
||||
run_func (&bsg, context().m_heap.get(), &wide_shadeindex.data(),
|
||||
userdata_base_ptr, output_base_ptr, run_mask.value());
|
||||
run_func(&bsg, context().m_heap.get(), &wide_shadeindex.data(),
|
||||
userdata_base_ptr, output_base_ptr, run_mask.value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,22 +332,24 @@ ShadingContext::Batched<WidthT>::execute_init( ShaderGroup &sgroup,
|
||||
|
||||
template<int WidthT>
|
||||
bool
|
||||
ShadingContext::Batched<WidthT>::execute_layer (int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT> &bsg,
|
||||
void* userdata_base_ptr,
|
||||
void* output_base_ptr,
|
||||
int layernumber)
|
||||
ShadingContext::Batched<WidthT>::execute_layer(
|
||||
int batch_size, Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT>& bsg, void* userdata_base_ptr,
|
||||
void* output_base_ptr, int layernumber)
|
||||
{
|
||||
if (!group() || group()->nlayers() == 0 || group()->does_nothing() || (context().batch_size_executed != batch_size))
|
||||
if (!group() || group()->nlayers() == 0 || group()->does_nothing()
|
||||
|| (context().batch_size_executed != batch_size))
|
||||
return false;
|
||||
OSL_DASSERT (bsg.uniform.context == &context() && bsg.uniform.renderer == context().renderer());
|
||||
OSL_DASSERT(bsg.uniform.context == &context()
|
||||
&& bsg.uniform.renderer == context().renderer());
|
||||
|
||||
int profile = shadingsys().m_profile;
|
||||
OIIO::Timer timer (profile ? OIIO::Timer::StartNow : OIIO::Timer::DontStartNow);
|
||||
OIIO::Timer timer(profile ? OIIO::Timer::StartNow
|
||||
: OIIO::Timer::DontStartNow);
|
||||
|
||||
RunLLVMGroupFuncWide run_func = group()->llvm_compiled_wide_layer (layernumber);
|
||||
if (! run_func)
|
||||
RunLLVMGroupFuncWide run_func = group()->llvm_compiled_wide_layer(
|
||||
layernumber);
|
||||
if (!run_func)
|
||||
return false;
|
||||
|
||||
OSL_ASSERT(pvt::is_aligned<64>(&bsg));
|
||||
@@ -349,8 +359,8 @@ ShadingContext::Batched<WidthT>::execute_layer (int batch_size,
|
||||
Mask<WidthT> run_mask(false);
|
||||
run_mask.set_count_on(batch_size);
|
||||
|
||||
run_func (&bsg, context().m_heap.get(), &wide_shadeindex.data(),
|
||||
userdata_base_ptr, output_base_ptr, run_mask.value());
|
||||
run_func(&bsg, context().m_heap.get(), &wide_shadeindex.data(),
|
||||
userdata_base_ptr, output_base_ptr, run_mask.value());
|
||||
}
|
||||
|
||||
if (profile)
|
||||
@@ -362,83 +372,85 @@ ShadingContext::Batched<WidthT>::execute_layer (int batch_size,
|
||||
|
||||
template<int WidthT>
|
||||
bool
|
||||
ShadingContext::Batched<WidthT>::execute(ShaderGroup &sgroup, int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex,
|
||||
BatchedShaderGlobals<WidthT> &bsg,
|
||||
void* userdata_base_ptr,
|
||||
void* output_base_ptr, bool run)
|
||||
ShadingContext::Batched<WidthT>::execute(
|
||||
ShaderGroup& sgroup, int batch_size,
|
||||
Wide<const int, WidthT> wide_shadeindex, BatchedShaderGlobals<WidthT>& bsg,
|
||||
void* userdata_base_ptr, void* output_base_ptr, bool run)
|
||||
{
|
||||
OSL_ASSERT(is_aligned<64>(&bsg));
|
||||
int n = sgroup.m_exec_repeat;
|
||||
|
||||
Block<Vec3,WidthT> Psave, Nsave; // for repeats
|
||||
Block<Vec3, WidthT> Psave, Nsave; // for repeats
|
||||
bool repeat = (n > 1);
|
||||
if (repeat) {
|
||||
// If we're going to repeat more than once, we need to save any
|
||||
// globals that might get modified.
|
||||
Psave = bsg.varying.P;
|
||||
Nsave = bsg.varying.N;
|
||||
if (! run)
|
||||
if (!run)
|
||||
n = 1;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
while (1) {
|
||||
if (! execute_init (sgroup, batch_size, wide_shadeindex, bsg,
|
||||
userdata_base_ptr, output_base_ptr, run))
|
||||
if (!execute_init(sgroup, batch_size, wide_shadeindex, bsg,
|
||||
userdata_base_ptr, output_base_ptr, run))
|
||||
return false;
|
||||
if (run && n)
|
||||
execute_layer (batch_size, wide_shadeindex, bsg,
|
||||
userdata_base_ptr, output_base_ptr,
|
||||
group()->nlayers()-1);
|
||||
result = context().execute_cleanup ();
|
||||
execute_layer(batch_size, wide_shadeindex, bsg, userdata_base_ptr,
|
||||
output_base_ptr, group()->nlayers() - 1);
|
||||
result = context().execute_cleanup();
|
||||
if (--n < 1)
|
||||
break; // done
|
||||
break; // done
|
||||
if (repeat) {
|
||||
// Going around for another pass... restore things as best as we
|
||||
// can.
|
||||
bsg.varying.P = Psave;
|
||||
bsg.varying.N = Nsave;
|
||||
bsg.uniform.Ci = NULL;
|
||||
assign_all(bsg.varying.Ci, (ClosureColor*)nullptr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
ShadingContext::record_error (ErrorHandler::ErrCode code,
|
||||
const std::string &text, Mask<MaxSupportedSimdLaneCount> mask) const
|
||||
ShadingContext::record_error(ErrorHandler::ErrCode code,
|
||||
const std::string& text,
|
||||
Mask<MaxSupportedSimdLaneCount> mask) const
|
||||
{
|
||||
m_buffered_errors.emplace_back (code,text, mask);
|
||||
m_buffered_errors.emplace_back(code, text, mask);
|
||||
// If we aren't buffering, just process immediately
|
||||
if (! shadingsys().m_buffer_printf)
|
||||
process_errors ();
|
||||
if (!shadingsys().m_buffer_printf)
|
||||
process_errors();
|
||||
}
|
||||
|
||||
void
|
||||
ShadingContext::record_to_file (ustring filename,
|
||||
const std::string &text, Mask<MaxSupportedSimdLaneCount> mask) const
|
||||
ShadingContext::record_to_file(ustring filename, const std::string& text,
|
||||
Mask<MaxSupportedSimdLaneCount> mask) const
|
||||
{
|
||||
m_buffered_file_output.emplace_back (filename,text, mask);
|
||||
m_buffered_file_output.emplace_back(filename, text, mask);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
ShadingContext::record_error (ErrorHandler::ErrCode code,
|
||||
const std::string &text) const
|
||||
ShadingContext::record_error(ErrorHandler::ErrCode code,
|
||||
const std::string& text) const
|
||||
{
|
||||
m_buffered_errors.emplace_back(code,text);
|
||||
m_buffered_errors.emplace_back(code, text);
|
||||
// If we aren't buffering, just process immediately
|
||||
if (! shadingsys().m_buffer_printf)
|
||||
process_errors ();
|
||||
if (!shadingsys().m_buffer_printf)
|
||||
process_errors();
|
||||
}
|
||||
|
||||
|
||||
// separate declaration from definition of template function
|
||||
// to ensure noinline is respected
|
||||
template<typename ErrorsT, typename TestFunctorT>
|
||||
static OSL_NOINLINE void process_errors_helper (ShadingSystemImpl &shading_sys, const ErrorsT &errors, int startAtError, int endBeforeError, const TestFunctorT & test_func);
|
||||
static OSL_NOINLINE void
|
||||
process_errors_helper(ShadingSystemImpl& shading_sys, const ErrorsT& errors,
|
||||
int startAtError, int endBeforeError,
|
||||
const TestFunctorT& test_func);
|
||||
|
||||
// Given array of ErrorItems emit errors within the range startAtError to
|
||||
// endBeforeError if and only if the test_func passed each ErrorItem's mask
|
||||
@@ -446,55 +458,57 @@ static OSL_NOINLINE void process_errors_helper (ShadingSystemImpl &shading_sys,
|
||||
// each data lane separately effectively serializing emission of errors,
|
||||
// warnings, info, and messages
|
||||
template<typename ErrorsT, typename TestFunctorT>
|
||||
void process_errors_helper (ShadingSystemImpl &shading_sys, const ErrorsT &errors, int startAtError, int endBeforeError, const TestFunctorT & test_func)
|
||||
void
|
||||
process_errors_helper(ShadingSystemImpl& shading_sys, const ErrorsT& errors,
|
||||
int startAtError, int endBeforeError,
|
||||
const TestFunctorT& test_func)
|
||||
{
|
||||
for (int i = startAtError; i < endBeforeError; ++i) {
|
||||
const auto & error_item = errors[i];
|
||||
for (int i = startAtError; i < endBeforeError; ++i) {
|
||||
const auto& error_item = errors[i];
|
||||
if (test_func(error_item.mask)) {
|
||||
switch (errors[i].err_code) {
|
||||
case ErrorHandler::EH_MESSAGE :
|
||||
case ErrorHandler::EH_DEBUG :
|
||||
shading_sys.message (error_item.msgString);
|
||||
case ErrorHandler::EH_MESSAGE:
|
||||
case ErrorHandler::EH_DEBUG:
|
||||
shading_sys.message(error_item.msgString);
|
||||
break;
|
||||
case ErrorHandler::EH_INFO :
|
||||
shading_sys.info (error_item.msgString);
|
||||
case ErrorHandler::EH_INFO:
|
||||
shading_sys.info(error_item.msgString);
|
||||
break;
|
||||
case ErrorHandler::EH_WARNING :
|
||||
shading_sys.warning (error_item.msgString);
|
||||
case ErrorHandler::EH_WARNING:
|
||||
shading_sys.warning(error_item.msgString);
|
||||
break;
|
||||
case ErrorHandler::EH_ERROR :
|
||||
case ErrorHandler::EH_SEVERE :
|
||||
shading_sys.error (error_item.msgString);
|
||||
break;
|
||||
default:
|
||||
case ErrorHandler::EH_ERROR:
|
||||
case ErrorHandler::EH_SEVERE:
|
||||
shading_sys.error(error_item.msgString);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShadingContext::process_errors () const
|
||||
ShadingContext::process_errors() const
|
||||
{
|
||||
int nerrors(m_buffered_errors.size());
|
||||
if (! nerrors)
|
||||
if (!nerrors)
|
||||
return;
|
||||
|
||||
// Use a mutex to make sure output from different threads stays
|
||||
// together, at least for one shader invocation, rather than being
|
||||
// interleaved with other threads.
|
||||
lock_guard lock (buffered_errors_mutex);
|
||||
lock_guard lock(buffered_errors_mutex);
|
||||
|
||||
#if OSL_USE_BATCHED
|
||||
if (execution_is_batched()) {
|
||||
OSL_DASSERT(batch_size_executed <= MaxSupportedSimdLaneCount);
|
||||
// Process each data lane separately and in the correct order
|
||||
for(int lane=0; lane < batch_size_executed; ++lane) {
|
||||
for (int lane = 0; lane < batch_size_executed; ++lane) {
|
||||
OSL_INTEL_PRAGMA(noinline)
|
||||
process_errors_helper(shadingsys(), m_buffered_errors, 0, nerrors,
|
||||
process_errors_helper(
|
||||
shadingsys(), m_buffered_errors, 0, nerrors,
|
||||
// Test Function returns true to process the ErrorItem
|
||||
[=](Mask<MaxSupportedSimdLaneCount> mask)->bool
|
||||
{
|
||||
[=](Mask<MaxSupportedSimdLaneCount> mask) -> bool {
|
||||
return mask.is_on(lane);
|
||||
});
|
||||
}
|
||||
@@ -503,10 +517,10 @@ ShadingContext::process_errors () const
|
||||
{
|
||||
// Non-batch errors: ignore the mask, just print them out once
|
||||
OSL_INTEL_PRAGMA(noinline)
|
||||
process_errors_helper(shadingsys(), m_buffered_errors, 0, nerrors,
|
||||
process_errors_helper(
|
||||
shadingsys(), m_buffered_errors, 0, nerrors,
|
||||
// Test Function returns true to process the ErrorItem
|
||||
[=](Mask<MaxSupportedSimdLaneCount> /*mask*/)->bool
|
||||
{
|
||||
[=](Mask<MaxSupportedSimdLaneCount> /*mask*/) -> bool {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@@ -515,29 +529,29 @@ ShadingContext::process_errors () const
|
||||
|
||||
#if OSL_USE_BATCHED
|
||||
void
|
||||
ShadingContext::process_file_output () const
|
||||
ShadingContext::process_file_output() const
|
||||
{
|
||||
int nerrors(m_buffered_file_output.size());
|
||||
if (! nerrors)
|
||||
if (!nerrors)
|
||||
return;
|
||||
|
||||
// Use a mutex to make sure output from different threads stays
|
||||
// together, at least for one shader invocation, rather than being
|
||||
// interleaved with other threads.
|
||||
lock_guard lock (buffered_file_output_mutex);
|
||||
lock_guard lock(buffered_file_output_mutex);
|
||||
|
||||
OSL_ASSERT(execution_is_batched());
|
||||
OSL_DASSERT(batch_size_executed <= MaxSupportedSimdLaneCount);
|
||||
// Process each data lane separately and in the correct order
|
||||
for(int lane=0; lane < batch_size_executed; ++lane) {
|
||||
for (int i = 0; i < nerrors; ++i) {
|
||||
const auto & item = m_buffered_file_output[i];
|
||||
if (item.mask.is_on(lane)){
|
||||
for (int lane = 0; lane < batch_size_executed; ++lane) {
|
||||
for (int i = 0; i < nerrors; ++i) {
|
||||
const auto& item = m_buffered_file_output[i];
|
||||
if (item.mask.is_on(lane)) {
|
||||
// TODO: if performance critical, one could keep a cache of
|
||||
// open files instead of closing and reopening
|
||||
FILE *file = fopen (item.filename.c_str(), "a");
|
||||
fputs (item.msgString.c_str(), file);
|
||||
fclose (file);
|
||||
FILE* file = fopen(item.filename.c_str(), "a");
|
||||
fputs(item.msgString.c_str(), file);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -545,32 +559,33 @@ ShadingContext::process_file_output () const
|
||||
}
|
||||
#endif
|
||||
|
||||
const Symbol *
|
||||
ShadingContext::symbol (ustring layername, ustring symbolname) const
|
||||
const Symbol*
|
||||
ShadingContext::symbol(ustring layername, ustring symbolname) const
|
||||
{
|
||||
return group()->find_symbol (layername, symbolname);
|
||||
return group()->find_symbol(layername, symbolname);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const void *
|
||||
ShadingContext::symbol_data (const Symbol &sym) const
|
||||
const void*
|
||||
ShadingContext::symbol_data(const Symbol& sym) const
|
||||
{
|
||||
const ShaderGroup &sgroup (*group());
|
||||
const ShaderGroup& sgroup(*group());
|
||||
#if OSL_USE_BATCHED
|
||||
if (execution_is_batched()) {
|
||||
if (! sgroup.batch_jitted())
|
||||
return NULL; // can't retrieve symbol if we didn't optimize & batched jit
|
||||
if (!sgroup.batch_jitted())
|
||||
return NULL; // can't retrieve symbol if we didn't optimize & batched jit
|
||||
|
||||
if (sym.wide_dataoffset() >= 0 && (int)m_heapsize > sym.wide_dataoffset()) {
|
||||
if (sym.wide_dataoffset() >= 0
|
||||
&& (int)m_heapsize > sym.wide_dataoffset()) {
|
||||
// lives on the heap
|
||||
return m_heap.get() + sym.wide_dataoffset();
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (! sgroup.jitted())
|
||||
return NULL; // can't retrieve symbol if we didn't optimize & jit
|
||||
if (!sgroup.jitted())
|
||||
return NULL; // can't retrieve symbol if we didn't optimize & jit
|
||||
|
||||
if (sym.dataoffset() >= 0 && (int)m_heapsize > sym.dataoffset()) {
|
||||
// lives on the heap
|
||||
@@ -581,8 +596,9 @@ ShadingContext::symbol_data (const Symbol &sym) const
|
||||
}
|
||||
|
||||
// doesn't live on the heap
|
||||
if ((sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam) &&
|
||||
(sym.valuesource() == Symbol::DefaultVal || sym.valuesource() == Symbol::InstanceVal)) {
|
||||
if ((sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam)
|
||||
&& (sym.valuesource() == Symbol::DefaultVal
|
||||
|| sym.valuesource() == Symbol::InstanceVal)) {
|
||||
// TODO(arenas): OSL_ASSERT(sym.arena() == SymArena::Absolute);
|
||||
return sym.dataptr();
|
||||
}
|
||||
@@ -593,9 +609,9 @@ ShadingContext::symbol_data (const Symbol &sym) const
|
||||
|
||||
|
||||
const std::regex&
|
||||
ShadingContext::find_regex (ustring r)
|
||||
ShadingContext::find_regex(ustring r)
|
||||
{
|
||||
RegexMap::const_iterator found = m_regex_map.find (r);
|
||||
RegexMap::const_iterator found = m_regex_map.find(r);
|
||||
if (found != m_regex_map.end())
|
||||
return *found->second;
|
||||
// otherwise, it wasn't found, add it
|
||||
@@ -608,11 +624,11 @@ ShadingContext::find_regex (ustring r)
|
||||
|
||||
|
||||
bool
|
||||
ShadingContext::osl_get_attribute (ShaderGlobals *sg, void *objdata,
|
||||
int dest_derivs,
|
||||
ustring obj_name, ustring attr_name,
|
||||
int array_lookup, int index,
|
||||
TypeDesc attr_type, void *attr_dest)
|
||||
ShadingContext::osl_get_attribute(ShaderGlobals* sg, void* objdata,
|
||||
int dest_derivs, ustring obj_name,
|
||||
ustring attr_name, int array_lookup,
|
||||
int index, TypeDesc attr_type,
|
||||
void* attr_dest)
|
||||
{
|
||||
#if 0
|
||||
// Change the #if's below if you want to
|
||||
@@ -621,13 +637,12 @@ ShadingContext::osl_get_attribute (ShaderGlobals *sg, void *objdata,
|
||||
bool ok;
|
||||
|
||||
if (array_lookup)
|
||||
ok = renderer()->get_array_attribute (sg, dest_derivs,
|
||||
obj_name, attr_type,
|
||||
attr_name, index, attr_dest);
|
||||
ok = renderer()->get_array_attribute(sg, dest_derivs, obj_name,
|
||||
attr_type, attr_name, index,
|
||||
attr_dest);
|
||||
else
|
||||
ok = renderer()->get_attribute (sg, dest_derivs,
|
||||
obj_name, attr_type,
|
||||
attr_name, attr_dest);
|
||||
ok = renderer()->get_attribute(sg, dest_derivs, obj_name, attr_type,
|
||||
attr_name, attr_dest);
|
||||
|
||||
#if 0
|
||||
double time = timer();
|
||||
@@ -636,17 +651,17 @@ ShadingContext::osl_get_attribute (ShaderGlobals *sg, void *objdata,
|
||||
shadingsys().m_stat_getattribute_fail_time += time;
|
||||
shadingsys().m_stat_getattribute_calls += 1;
|
||||
#endif
|
||||
// std::cout << "getattribute! '" << obj_name << "' " << attr_name << ' ' << attr_type.c_str() << " ok=" << ok << ", objdata was " << objdata << "\n";
|
||||
// std::cout << "getattribute! '" << obj_name << "' " << attr_name << ' ' << attr_type.c_str() << " ok=" << ok << ", objdata was " << objdata << "\n";
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
OSL_SHADEOP void
|
||||
osl_incr_layers_executed (ShaderGlobals *sg)
|
||||
osl_incr_layers_executed(ShaderGlobals* sg)
|
||||
{
|
||||
ShadingContext *ctx = (ShadingContext *)sg->context;
|
||||
ctx->incr_layers_executed ();
|
||||
ShadingContext* ctx = (ShadingContext*)sg->context;
|
||||
ctx->incr_layers_executed();
|
||||
}
|
||||
|
||||
#if OSL_USE_BATCHED
|
||||
|
||||
+146
-137
@@ -2,12 +2,12 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <OpenImageIO/strutil.h>
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace pugi = OIIO::pugi;
|
||||
|
||||
OSL_NAMESPACE_ENTER
|
||||
|
||||
namespace pvt { // OSL::pvt
|
||||
namespace pvt { // OSL::pvt
|
||||
|
||||
|
||||
// Helper class to manage the dictionaries.
|
||||
@@ -46,21 +46,22 @@ namespace pvt { // OSL::pvt
|
||||
//
|
||||
class Dictionary {
|
||||
public:
|
||||
Dictionary (ShadingContext *ctx) : m_context(ctx)
|
||||
Dictionary(ShadingContext* ctx) : m_context(ctx)
|
||||
{
|
||||
// Create placeholder element 0 == 'not found'
|
||||
m_nodes.emplace_back(0, pugi::xml_node());
|
||||
}
|
||||
~Dictionary () {
|
||||
~Dictionary()
|
||||
{
|
||||
// Free all the documents.
|
||||
for (auto& doc : m_documents)
|
||||
delete doc;
|
||||
}
|
||||
|
||||
int dict_find (ustring dictionaryname, ustring query);
|
||||
int dict_find (int nodeID, ustring query);
|
||||
int dict_next (int nodeID);
|
||||
int dict_value (int nodeID, ustring attribname, TypeDesc type, void *data);
|
||||
int dict_find(ustring dictionaryname, ustring query);
|
||||
int dict_find(int nodeID, ustring query);
|
||||
int dict_next(int nodeID);
|
||||
int dict_value(int nodeID, ustring attribname, TypeDesc type, void* data);
|
||||
|
||||
private:
|
||||
// We cache individual queries with a key that is a tuple of the
|
||||
@@ -70,19 +71,23 @@ private:
|
||||
int node; // root node for the search
|
||||
ustring name; // name for the the search
|
||||
TypeDesc type; // UNKNOWN signifies a node, versus an attribute value
|
||||
Query (int doc_, int node_, ustring name_,
|
||||
TypeDesc type_=TypeDesc::UNKNOWN) :
|
||||
document(doc_), node(node_), name(name_), type(type_) { }
|
||||
bool operator== (const Query &q) const {
|
||||
return document == q.document && node == q.node &&
|
||||
name == q.name && type == q.type;
|
||||
Query(int doc_, int node_, ustring name_,
|
||||
TypeDesc type_ = TypeDesc::UNKNOWN)
|
||||
: document(doc_), node(node_), name(name_), type(type_)
|
||||
{
|
||||
}
|
||||
bool operator==(const Query& q) const
|
||||
{
|
||||
return document == q.document && node == q.node && name == q.name
|
||||
&& type == q.type;
|
||||
}
|
||||
};
|
||||
|
||||
// Must define a hash operation to build the unordered_map.
|
||||
struct QueryHash {
|
||||
size_t operator() (const Query &key) const {
|
||||
return key.name.hash() + 17*key.node + 79*key.document;
|
||||
size_t operator()(const Query& key) const
|
||||
{
|
||||
return key.name.hash() + 17 * key.node + 79 * key.document;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -93,9 +98,11 @@ private:
|
||||
struct QueryResult {
|
||||
int valueoffset; // Offset into one of the 'data' vectors, or nodeID
|
||||
bool is_valid; // true: query found
|
||||
QueryResult (bool valid=true) : valueoffset(0), is_valid(valid) { }
|
||||
QueryResult (bool /*isnode*/, int value)
|
||||
: valueoffset(value), is_valid(true) { }
|
||||
QueryResult(bool valid = true) : valueoffset(0), is_valid(valid) {}
|
||||
QueryResult(bool /*isnode*/, int value)
|
||||
: valueoffset(value), is_valid(true)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Nodes we've looked up. Includes a 'next' index of the matching node
|
||||
@@ -104,17 +111,16 @@ private:
|
||||
int document; // which document the node belongs to
|
||||
pugi::xml_node node; // which node within the dictionary
|
||||
int next; // next node for the same query
|
||||
Node (int d, const pugi::xml_node &n)
|
||||
: document(d), node(n), next(0) { }
|
||||
Node(int d, const pugi::xml_node& n) : document(d), node(n), next(0) {}
|
||||
};
|
||||
|
||||
typedef std::unordered_map <Query, QueryResult, QueryHash> QueryMap;
|
||||
typedef std::unordered_map<ustring, int, ustringHash> DocMap;
|
||||
typedef std::unordered_map<Query, QueryResult, QueryHash> QueryMap;
|
||||
typedef std::unordered_map<ustring, int> DocMap;
|
||||
|
||||
ShadingContext *m_context; // back-pointer to shading context
|
||||
ShadingContext* m_context; // back-pointer to shading context
|
||||
|
||||
// List of XML documents we've read in.
|
||||
std::vector<pugi::xml_document *> m_documents;
|
||||
std::vector<pugi::xml_document*> m_documents;
|
||||
|
||||
// Map xml strings and/or filename to indices in m_documents.
|
||||
DocMap m_document_map;
|
||||
@@ -127,38 +133,38 @@ private:
|
||||
|
||||
// m_floatdata, m_intdata, and m_stringdata hold the decoded data
|
||||
// results (including type conversion) of cached queries.
|
||||
std::vector<float> m_floatdata;
|
||||
std::vector<int> m_intdata;
|
||||
std::vector<float> m_floatdata;
|
||||
std::vector<int> m_intdata;
|
||||
std::vector<ustring> m_stringdata;
|
||||
|
||||
// Helper function: return the document index given dictionary name.
|
||||
int get_document_index (ustring dictionaryname);
|
||||
int get_document_index(ustring dictionaryname);
|
||||
};
|
||||
|
||||
|
||||
|
||||
int
|
||||
Dictionary::get_document_index (ustring dictionaryname)
|
||||
Dictionary::get_document_index(ustring dictionaryname)
|
||||
{
|
||||
DocMap::iterator dm = m_document_map.find(dictionaryname);
|
||||
int dindex;
|
||||
if (dm == m_document_map.end()) {
|
||||
dindex = m_documents.size();
|
||||
dindex = m_documents.size();
|
||||
m_document_map[dictionaryname] = dindex;
|
||||
pugi::xml_document *doc = new pugi::xml_document;
|
||||
m_documents.push_back (doc);
|
||||
pugi::xml_document* doc = new pugi::xml_document;
|
||||
m_documents.push_back(doc);
|
||||
pugi::xml_parse_result parse_result;
|
||||
if (Strutil::ends_with(dictionaryname, ".xml")) {
|
||||
// xml file -- read it
|
||||
parse_result = doc->load_file (dictionaryname.c_str());
|
||||
parse_result = doc->load_file(dictionaryname.c_str());
|
||||
} else {
|
||||
// load xml directly from the string
|
||||
parse_result = doc->load_string(dictionaryname.c_str());
|
||||
}
|
||||
if (! parse_result) {
|
||||
m_context->errorf("XML parsed with errors: %s, at offset %d",
|
||||
parse_result.description(),
|
||||
parse_result.offset);
|
||||
if (!parse_result) {
|
||||
m_context->errorfmt("XML parsed with errors: {}, at offset {}",
|
||||
parse_result.description(),
|
||||
parse_result.offset);
|
||||
m_document_map[dictionaryname] = -1;
|
||||
return -1;
|
||||
}
|
||||
@@ -173,44 +179,43 @@ Dictionary::get_document_index (ustring dictionaryname)
|
||||
|
||||
|
||||
int
|
||||
Dictionary::dict_find (ustring dictionaryname, ustring query)
|
||||
Dictionary::dict_find(ustring dictionaryname, ustring query)
|
||||
{
|
||||
int dindex = get_document_index (dictionaryname);
|
||||
int dindex = get_document_index(dictionaryname);
|
||||
if (dindex < 0)
|
||||
return dindex;
|
||||
|
||||
Query q (dindex, 0, query);
|
||||
QueryMap::iterator qfound = m_cache.find (q);
|
||||
Query q(dindex, 0, query);
|
||||
QueryMap::iterator qfound = m_cache.find(q);
|
||||
if (qfound != m_cache.end()) {
|
||||
return qfound->second.valueoffset;
|
||||
}
|
||||
|
||||
pugi::xml_document *doc = m_documents[dindex];
|
||||
pugi::xml_document* doc = m_documents[dindex];
|
||||
|
||||
// Query was not found. Do the expensive lookup and cache it
|
||||
pugi::xpath_node_set matches;
|
||||
|
||||
try {
|
||||
matches = doc->select_nodes (query.c_str());
|
||||
}
|
||||
catch (const pugi::xpath_exception& e) {
|
||||
m_context->errorf("Invalid dict_find query '%s': %s",
|
||||
query.c_str(), e.what());
|
||||
matches = doc->select_nodes(query.c_str());
|
||||
} catch (const pugi::xpath_exception& e) {
|
||||
m_context->errorfmt("Invalid dict_find query '{}': {}", query,
|
||||
e.what());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (matches.empty()) {
|
||||
m_cache[q] = QueryResult (false); // mark invalid
|
||||
return 0; // Not found
|
||||
m_cache[q] = QueryResult(false); // mark invalid
|
||||
return 0; // Not found
|
||||
}
|
||||
int firstmatch = (int) m_nodes.size();
|
||||
int last = -1;
|
||||
int firstmatch = (int)m_nodes.size();
|
||||
int last = -1;
|
||||
for (auto&& m : matches) {
|
||||
m_nodes.emplace_back(dindex, m.node());
|
||||
int nodeid = (int) m_nodes.size()-1;
|
||||
int nodeid = (int)m_nodes.size() - 1;
|
||||
if (last < 0) {
|
||||
// If this is the first match, add a cache entry for it
|
||||
m_cache[q] = QueryResult (true /* it's a node */, nodeid);
|
||||
m_cache[q] = QueryResult(true /* it's a node */, nodeid);
|
||||
} else {
|
||||
// If this is a subsequent match, set the last match's 'next'
|
||||
m_nodes[last].next = nodeid;
|
||||
@@ -223,14 +228,14 @@ Dictionary::dict_find (ustring dictionaryname, ustring query)
|
||||
|
||||
|
||||
int
|
||||
Dictionary::dict_find (int nodeID, ustring query)
|
||||
Dictionary::dict_find(int nodeID, ustring query)
|
||||
{
|
||||
if (nodeID <= 0 || nodeID >= (int)m_nodes.size())
|
||||
return 0; // invalid node ID
|
||||
return 0; // invalid node ID
|
||||
|
||||
int document = m_nodes[nodeID].document;
|
||||
Query q (document, nodeID, query);
|
||||
QueryMap::iterator qfound = m_cache.find (q);
|
||||
Query q(document, nodeID, query);
|
||||
QueryMap::iterator qfound = m_cache.find(q);
|
||||
if (qfound != m_cache.end()) {
|
||||
return qfound->second.valueoffset;
|
||||
}
|
||||
@@ -238,26 +243,25 @@ Dictionary::dict_find (int nodeID, ustring query)
|
||||
// Query was not found. Do the expensive lookup and cache it
|
||||
pugi::xpath_node_set matches;
|
||||
try {
|
||||
matches = m_nodes[nodeID].node.select_nodes (query.c_str());
|
||||
}
|
||||
catch (const pugi::xpath_exception& e) {
|
||||
m_context->errorf("Invalid dict_find query '%s': %s",
|
||||
query.c_str(), e.what());
|
||||
matches = m_nodes[nodeID].node.select_nodes(query.c_str());
|
||||
} catch (const pugi::xpath_exception& e) {
|
||||
m_context->errorfmt("Invalid dict_find query '{}': {}", query,
|
||||
e.what());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (matches.empty()) {
|
||||
m_cache[q] = QueryResult (false); // mark invalid
|
||||
return 0; // Not found
|
||||
m_cache[q] = QueryResult(false); // mark invalid
|
||||
return 0; // Not found
|
||||
}
|
||||
int firstmatch = (int) m_nodes.size();
|
||||
int last = -1;
|
||||
int firstmatch = (int)m_nodes.size();
|
||||
int last = -1;
|
||||
for (auto&& m : matches) {
|
||||
m_nodes.emplace_back(document, m.node());
|
||||
int nodeid = (int) m_nodes.size()-1;
|
||||
int nodeid = (int)m_nodes.size() - 1;
|
||||
if (last < 0) {
|
||||
// If this is the first match, add a cache entry for it
|
||||
m_cache[q] = QueryResult (true /* it's a node */, nodeid);
|
||||
m_cache[q] = QueryResult(true /* it's a node */, nodeid);
|
||||
} else {
|
||||
// If this is a subsequent match, set the last match's 'next'
|
||||
m_nodes[last].next = nodeid;
|
||||
@@ -270,42 +274,42 @@ Dictionary::dict_find (int nodeID, ustring query)
|
||||
|
||||
|
||||
int
|
||||
Dictionary::dict_next (int nodeID)
|
||||
Dictionary::dict_next(int nodeID)
|
||||
{
|
||||
if (nodeID <= 0 || nodeID >= (int)m_nodes.size())
|
||||
return 0; // invalid node ID
|
||||
return 0; // invalid node ID
|
||||
return m_nodes[nodeID].next;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
Dictionary::dict_value (int nodeID, ustring attribname,
|
||||
TypeDesc type, void *data)
|
||||
Dictionary::dict_value(int nodeID, ustring attribname, TypeDesc type,
|
||||
void* data)
|
||||
{
|
||||
if (nodeID <= 0 || nodeID >= (int)m_nodes.size())
|
||||
return 0; // invalid node ID
|
||||
return 0; // invalid node ID
|
||||
|
||||
const Dictionary::Node &node (m_nodes[nodeID]);
|
||||
Dictionary::Query q (node.document, nodeID, attribname, type);
|
||||
Dictionary::QueryMap::iterator qfound = m_cache.find (q);
|
||||
const Dictionary::Node& node(m_nodes[nodeID]);
|
||||
Dictionary::Query q(node.document, nodeID, attribname, type);
|
||||
Dictionary::QueryMap::iterator qfound = m_cache.find(q);
|
||||
if (qfound != m_cache.end()) {
|
||||
// previously found
|
||||
int offset = qfound->second.valueoffset;
|
||||
int n = type.numelements() * type.aggregate;
|
||||
int n = type.numelements() * type.aggregate;
|
||||
if (type.basetype == TypeDesc::STRING) {
|
||||
OSL_DASSERT (n == 1 && "no string arrays in XML");
|
||||
((ustring *)data)[0] = m_stringdata[offset];
|
||||
OSL_DASSERT(n == 1 && "no string arrays in XML");
|
||||
((ustring*)data)[0] = m_stringdata[offset];
|
||||
return 1;
|
||||
}
|
||||
if (type.basetype == TypeDesc::INT) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
((int *)data)[i] = m_intdata[offset++];
|
||||
for (int i = 0; i < n; ++i)
|
||||
((int*)data)[i] = m_intdata[offset++];
|
||||
return 1;
|
||||
}
|
||||
if (type.basetype == TypeDesc::FLOAT) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
((float *)data)[i] = m_floatdata[offset++];
|
||||
for (int i = 0; i < n; ++i)
|
||||
((float*)data)[i] = m_floatdata[offset++];
|
||||
return 1;
|
||||
}
|
||||
return 0; // Unknown type
|
||||
@@ -313,7 +317,7 @@ Dictionary::dict_value (int nodeID, ustring attribname,
|
||||
|
||||
// OK, the entry wasn't in the cache, we need to decode it and cache it.
|
||||
|
||||
const char *val = NULL;
|
||||
const char* val = NULL;
|
||||
if (attribname.empty()) {
|
||||
val = node.node.value();
|
||||
} else {
|
||||
@@ -326,40 +330,40 @@ Dictionary::dict_value (int nodeID, ustring attribname,
|
||||
}
|
||||
}
|
||||
if (val == NULL)
|
||||
return 0; // not found
|
||||
return 0; // not found
|
||||
|
||||
Dictionary::QueryResult r (false, 0);
|
||||
Dictionary::QueryResult r(false, 0);
|
||||
int n = type.numelements() * type.aggregate;
|
||||
if (type.basetype == TypeDesc::STRING && n == 1) {
|
||||
r.valueoffset = (int) m_stringdata.size();
|
||||
ustring s (val);
|
||||
m_stringdata.push_back (s);
|
||||
((ustring *)data)[0] = s;
|
||||
m_cache[q] = r;
|
||||
r.valueoffset = (int)m_stringdata.size();
|
||||
ustring s(val);
|
||||
m_stringdata.push_back(s);
|
||||
((ustring*)data)[0] = s;
|
||||
m_cache[q] = r;
|
||||
return 1;
|
||||
}
|
||||
if (type.basetype == TypeDesc::INT) {
|
||||
r.valueoffset = (int) m_intdata.size();
|
||||
string_view valstr (val);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
r.valueoffset = (int)m_intdata.size();
|
||||
string_view valstr(val);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int v;
|
||||
OIIO::Strutil::parse_int (valstr, v);
|
||||
OIIO::Strutil::parse_char (valstr, ',');
|
||||
m_intdata.push_back (v);
|
||||
((int *)data)[i] = v;
|
||||
OIIO::Strutil::parse_int(valstr, v);
|
||||
OIIO::Strutil::parse_char(valstr, ',');
|
||||
m_intdata.push_back(v);
|
||||
((int*)data)[i] = v;
|
||||
}
|
||||
m_cache[q] = r;
|
||||
return 1;
|
||||
}
|
||||
if (type.basetype == TypeDesc::FLOAT) {
|
||||
r.valueoffset = (int) m_floatdata.size();
|
||||
string_view valstr (val);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
r.valueoffset = (int)m_floatdata.size();
|
||||
string_view valstr(val);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
float v;
|
||||
OIIO::Strutil::parse_float (valstr, v);
|
||||
OIIO::Strutil::parse_char (valstr, ',');
|
||||
m_floatdata.push_back (v);
|
||||
((float *)data)[i] = v;
|
||||
OIIO::Strutil::parse_float(valstr, v);
|
||||
OIIO::Strutil::parse_char(valstr, ',');
|
||||
m_floatdata.push_back(v);
|
||||
((float*)data)[i] = v;
|
||||
}
|
||||
m_cache[q] = r;
|
||||
return 1;
|
||||
@@ -370,90 +374,95 @@ Dictionary::dict_value (int nodeID, ustring attribname,
|
||||
}
|
||||
|
||||
|
||||
}; // namespace pvt
|
||||
}; // namespace pvt
|
||||
|
||||
|
||||
|
||||
int
|
||||
ShadingContext::dict_find (ustring dictionaryname, ustring query)
|
||||
ShadingContext::dict_find(ustring dictionaryname, ustring query)
|
||||
{
|
||||
if (! m_dictionary) {
|
||||
m_dictionary = new Dictionary (this);
|
||||
if (!m_dictionary) {
|
||||
m_dictionary = new Dictionary(this);
|
||||
}
|
||||
return m_dictionary->dict_find (dictionaryname, query);
|
||||
return m_dictionary->dict_find(dictionaryname, query);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
ShadingContext::dict_find (int nodeID, ustring query)
|
||||
ShadingContext::dict_find(int nodeID, ustring query)
|
||||
{
|
||||
if (! m_dictionary) {
|
||||
m_dictionary = new Dictionary (this);
|
||||
if (!m_dictionary) {
|
||||
m_dictionary = new Dictionary(this);
|
||||
}
|
||||
return m_dictionary->dict_find (nodeID, query);
|
||||
return m_dictionary->dict_find(nodeID, query);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
ShadingContext::dict_next (int nodeID)
|
||||
ShadingContext::dict_next(int nodeID)
|
||||
{
|
||||
if (! m_dictionary)
|
||||
if (!m_dictionary)
|
||||
return 0;
|
||||
return m_dictionary->dict_next (nodeID);
|
||||
return m_dictionary->dict_next(nodeID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
ShadingContext::dict_value (int nodeID, ustring attribname,
|
||||
TypeDesc type, void *data)
|
||||
ShadingContext::dict_value(int nodeID, ustring attribname, TypeDesc type,
|
||||
void* data)
|
||||
{
|
||||
if (! m_dictionary)
|
||||
if (!m_dictionary)
|
||||
return 0;
|
||||
return m_dictionary->dict_value (nodeID, attribname, type, data);
|
||||
return m_dictionary->dict_value(nodeID, attribname, type, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ShadingContext::free_dict_resources ()
|
||||
ShadingContext::free_dict_resources()
|
||||
{
|
||||
delete m_dictionary;
|
||||
}
|
||||
|
||||
|
||||
|
||||
OSL_SHADEOP int osl_dict_find_iis (void *sg_, int nodeID, void *query)
|
||||
OSL_SHADEOP int
|
||||
osl_dict_find_iis(void* sg_, int nodeID, void* query)
|
||||
{
|
||||
ShaderGlobals *sg = (ShaderGlobals *)sg_;
|
||||
return sg->context->dict_find (nodeID, USTR(query));
|
||||
ShaderGlobals* sg = (ShaderGlobals*)sg_;
|
||||
return sg->context->dict_find(nodeID, USTR(query));
|
||||
}
|
||||
|
||||
|
||||
|
||||
OSL_SHADEOP int osl_dict_find_iss (void *sg_, void *dictionary, void *query)
|
||||
OSL_SHADEOP int
|
||||
osl_dict_find_iss(void* sg_, void* dictionary, void* query)
|
||||
{
|
||||
ShaderGlobals *sg = (ShaderGlobals *)sg_;
|
||||
return sg->context->dict_find (USTR(dictionary), USTR(query));
|
||||
ShaderGlobals* sg = (ShaderGlobals*)sg_;
|
||||
return sg->context->dict_find(USTR(dictionary), USTR(query));
|
||||
}
|
||||
|
||||
|
||||
|
||||
OSL_SHADEOP int osl_dict_next (void *sg_, int nodeID)
|
||||
OSL_SHADEOP int
|
||||
osl_dict_next(void* sg_, int nodeID)
|
||||
{
|
||||
ShaderGlobals *sg = (ShaderGlobals *)sg_;
|
||||
return sg->context->dict_next (nodeID);
|
||||
ShaderGlobals* sg = (ShaderGlobals*)sg_;
|
||||
return sg->context->dict_next(nodeID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
OSL_SHADEOP int osl_dict_value (void *sg_, int nodeID, void *attribname,
|
||||
long long type, void *data)
|
||||
OSL_SHADEOP int
|
||||
osl_dict_value(void* sg_, int nodeID, void* attribname, long long type,
|
||||
void* data)
|
||||
{
|
||||
ShaderGlobals *sg = (ShaderGlobals *)sg_;
|
||||
return sg->context->dict_value (nodeID, USTR(attribname), TYPEDESC(type), data);
|
||||
ShaderGlobals* sg = (ShaderGlobals*)sg_;
|
||||
return sg->context->dict_value(nodeID, USTR(attribname), TYPEDESC(type),
|
||||
data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,22 +4,23 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <OSL/oslconfig.h>
|
||||
#include <OSL/dual.h>
|
||||
#include <OSL/dual_vec.h>
|
||||
#include <OSL/oslconfig.h>
|
||||
|
||||
#include <OpenImageIO/benchmark.h>
|
||||
#include <OpenImageIO/unittest.h>
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
typedef Dual<float,1> Dualf;
|
||||
typedef Dual<float, 1> Dualf;
|
||||
typedef Dual2<float> Dual2f;
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
T crazy (const T& x)
|
||||
T
|
||||
crazy(const T& x)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace OSL;
|
||||
@@ -29,11 +30,12 @@ T crazy (const T& x)
|
||||
|
||||
|
||||
template<class T>
|
||||
T crazy (const T& x, const T& y)
|
||||
T
|
||||
crazy(const T& x, const T& y)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace OSL;
|
||||
return x * y * exp(x+y);
|
||||
return x * y * exp(x + y);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,19 +43,21 @@ T crazy (const T& x, const T& y)
|
||||
// Compare 1D derivs with Duals to numerical differentiation. This sure
|
||||
// isn't comprehensive, but it tests the general scheme.
|
||||
void
|
||||
test_derivs1 () {
|
||||
const float eps = 1e-3;
|
||||
test_derivs1()
|
||||
{
|
||||
const float eps = 1e-3;
|
||||
static float domain[] = { 0, 0.1, 0.25, 0.333333, 0.91 };
|
||||
for (auto x : domain) {
|
||||
float f = crazy(x);
|
||||
float df_numeric = (crazy(x+eps) - crazy(x-eps)) / (2.0f*eps);
|
||||
Dual<float> xd (x, 1.0f);
|
||||
Dual<float> fd = crazy (xd);
|
||||
std::cout << "crazy(" << x << ")=" << f << ", numeric derivs ~= "
|
||||
<< df_numeric << ", Dual f = " << fd << "\n";
|
||||
float f = crazy(x);
|
||||
float df_numeric = (crazy(x + eps) - crazy(x - eps)) / (2.0f * eps);
|
||||
Dual<float> xd(x, 1.0f);
|
||||
Dual<float> fd = crazy(xd);
|
||||
std::cout << "crazy(" << x << ")=" << f
|
||||
<< ", numeric derivs ~= " << df_numeric << ", Dual f = " << fd
|
||||
<< "\n";
|
||||
|
||||
OIIO_CHECK_EQUAL_THRESH (f, fd.val(), eps);
|
||||
OIIO_CHECK_EQUAL_THRESH (df_numeric, fd.dx(), eps);
|
||||
OIIO_CHECK_EQUAL_THRESH(f, fd.val(), eps);
|
||||
OIIO_CHECK_EQUAL_THRESH(df_numeric, fd.dx(), eps);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,25 +66,28 @@ test_derivs1 () {
|
||||
// Compare 2D derivs with Duals to numerical differentiation. This sure
|
||||
// isn't comprehensive, but it tests the general scheme.
|
||||
void
|
||||
test_derivs2 () {
|
||||
const float eps = 1e-3;
|
||||
test_derivs2()
|
||||
{
|
||||
const float eps = 1e-3;
|
||||
static float domain[] = { 0, 0.1, 0.25, 0.333333, 0.91 };
|
||||
for (auto x : domain) {
|
||||
for (auto y : domain) {
|
||||
float f = crazy(x,y);
|
||||
float df_dx_numeric = (crazy(x+eps,y) - crazy(x-eps,y)) / (2.0f*eps);
|
||||
float df_dy_numeric = (crazy(x,y+eps) - crazy(x,y-eps)) / (2.0f*eps);
|
||||
Dual<float,2> xd (x, 1.0f, 0.0f);
|
||||
Dual<float,2> yd (y, 0.0f, 1.0f);
|
||||
Dual<float,2> fd = crazy (xd, yd);
|
||||
float f = crazy(x, y);
|
||||
float df_dx_numeric = (crazy(x + eps, y) - crazy(x - eps, y))
|
||||
/ (2.0f * eps);
|
||||
float df_dy_numeric = (crazy(x, y + eps) - crazy(x, y - eps))
|
||||
/ (2.0f * eps);
|
||||
Dual<float, 2> xd(x, 1.0f, 0.0f);
|
||||
Dual<float, 2> yd(y, 0.0f, 1.0f);
|
||||
Dual<float, 2> fd = crazy(xd, yd);
|
||||
std::cout << "crazy(" << x << "," << y << ")=" << f
|
||||
<< ", numeric derivs df/dx ~= "
|
||||
<< df_dx_numeric << ", df/dy ~= " << df_dy_numeric
|
||||
<< ", Dual f = " << fd << "\n";
|
||||
<< ", numeric derivs df/dx ~= " << df_dx_numeric
|
||||
<< ", df/dy ~= " << df_dy_numeric << ", Dual f = " << fd
|
||||
<< "\n";
|
||||
|
||||
OIIO_CHECK_EQUAL_THRESH (f, fd.val(), eps);
|
||||
OIIO_CHECK_EQUAL_THRESH (df_dx_numeric, fd.dx(), eps);
|
||||
OIIO_CHECK_EQUAL_THRESH (df_dy_numeric, fd.dy(), eps);
|
||||
OIIO_CHECK_EQUAL_THRESH(f, fd.val(), eps);
|
||||
OIIO_CHECK_EQUAL_THRESH(df_dx_numeric, fd.dx(), eps);
|
||||
OIIO_CHECK_EQUAL_THRESH(df_dy_numeric, fd.dy(), eps);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,33 +95,34 @@ test_derivs2 () {
|
||||
|
||||
|
||||
void
|
||||
test_metaprogramming ()
|
||||
test_metaprogramming()
|
||||
{
|
||||
// Does is_Dual<> correctly discern duals from non-duals?
|
||||
OIIO_CHECK_ASSERT (is_Dual<Dualf>());
|
||||
OIIO_CHECK_ASSERT (is_Dual<Dual2f>());
|
||||
OIIO_CHECK_ASSERT (! is_Dual<float>());
|
||||
OIIO_CHECK_ASSERT (! is_Dual<Vec3>());
|
||||
OIIO_CHECK_ASSERT(is_Dual<Dualf>());
|
||||
OIIO_CHECK_ASSERT(is_Dual<Dual2f>());
|
||||
OIIO_CHECK_ASSERT(!is_Dual<float>());
|
||||
OIIO_CHECK_ASSERT(!is_Dual<Vec3>());
|
||||
|
||||
// Does Dualify<> correctly turn a scalar into a dual?
|
||||
OIIO_CHECK_ASSERT ((std::is_same<Dualify<float>::type, Dualf>::value));
|
||||
OIIO_CHECK_ASSERT ((std::is_same<Dualify<float,2>::type, Dual2f>::value));
|
||||
OIIO_CHECK_ASSERT ((std::is_same<Dualify<Dualf,1>::type, Dualf>::value));
|
||||
OIIO_CHECK_ASSERT ((std::is_same<Dualify<Dual2f,2>::type, Dual2f>::value));
|
||||
OIIO_CHECK_ASSERT((std::is_same<Dualify<float>::type, Dualf>::value));
|
||||
OIIO_CHECK_ASSERT((std::is_same<Dualify<float, 2>::type, Dual2f>::value));
|
||||
OIIO_CHECK_ASSERT((std::is_same<Dualify<Dualf, 1>::type, Dualf>::value));
|
||||
OIIO_CHECK_ASSERT((std::is_same<Dualify<Dual2f, 2>::type, Dual2f>::value));
|
||||
|
||||
OIIO_CHECK_ASSERT ((std::is_same<UnDual<float >::type, float>::value));
|
||||
OIIO_CHECK_ASSERT ((std::is_same<UnDual<Vec3 >::type, Vec3> ::value));
|
||||
OIIO_CHECK_ASSERT ((std::is_same<UnDual<Dualf >::type, float>::value));
|
||||
OIIO_CHECK_ASSERT ((std::is_same<UnDual<Dual2f>::type, float>::value));
|
||||
OIIO_CHECK_ASSERT((std::is_same<UnDual<float>::type, float>::value));
|
||||
OIIO_CHECK_ASSERT((std::is_same<UnDual<Vec3>::type, Vec3>::value));
|
||||
OIIO_CHECK_ASSERT((std::is_same<UnDual<Dualf>::type, float>::value));
|
||||
OIIO_CHECK_ASSERT((std::is_same<UnDual<Dual2f>::type, float>::value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int /*argc*/, char * /*argv*/[])
|
||||
int
|
||||
main(int /*argc*/, char* /*argv*/[])
|
||||
{
|
||||
test_metaprogramming ();
|
||||
test_derivs1 ();
|
||||
test_derivs2 ();
|
||||
test_metaprogramming();
|
||||
test_derivs1();
|
||||
test_derivs2();
|
||||
|
||||
// Some benchmarking
|
||||
std::cout << "\nBenchmarks:\n";
|
||||
@@ -122,9 +130,14 @@ int main(int /*argc*/, char * /*argv*/[])
|
||||
Benchmarker bench;
|
||||
Dual2f v(1.5f, 0.01f, 0.01f);
|
||||
clobber(v);
|
||||
bench("-Dual2f", [&](const Dual2f& v) { return DoNotOptimize(-v); }, v);
|
||||
bench("fast_neg(Dual2f)", [&](const Dual2f& v) { return DoNotOptimize(fast_neg(v)); }, v);
|
||||
bench("log2(Dual2f)", [&](const Dual2f& v) { return DoNotOptimize(fast_log2(v)); }, v);
|
||||
bench(
|
||||
"-Dual2f", [&](const Dual2f& v) { return DoNotOptimize(-v); }, v);
|
||||
bench(
|
||||
"fast_neg(Dual2f)",
|
||||
[&](const Dual2f& v) { return DoNotOptimize(fast_neg(v)); }, v);
|
||||
bench(
|
||||
"log2(Dual2f)",
|
||||
[&](const Dual2f& v) { return DoNotOptimize(fast_log2(v)); }, v);
|
||||
|
||||
// FIXME: Some day, expand to more exhaustive tests of Dual
|
||||
|
||||
|
||||
+321
-287
File diff suppressed because it is too large
Load Diff
+1859
-1851
File diff suppressed because it is too large
Load Diff
+662
-577
File diff suppressed because it is too large
Load Diff
+522
-391
File diff suppressed because it is too large
Load Diff
+159
-85
@@ -6,14 +6,14 @@
|
||||
|
||||
#include <OSL/oslconfig.h>
|
||||
|
||||
#include <llvm/Pass.h>
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
#include <llvm/IR/DerivedTypes.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/Instruction.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
#include <llvm/Pass.h>
|
||||
#include <llvm/Support/Casting.h>
|
||||
|
||||
OSL_NAMESPACE_ENTER
|
||||
@@ -37,16 +37,18 @@ namespace {
|
||||
// how instruction lowering happens then this pass may not be necessary.
|
||||
// Also if future LLVM version takes on the work of this optimization pass,
|
||||
// then it may be removed.
|
||||
template <int WidthT>
|
||||
template<int WidthT>
|
||||
class PreventBitMasksFromBeingLiveinsToBasicBlocks final
|
||||
: public llvm::FunctionPass
|
||||
{
|
||||
typedef llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter> IRBuilder;
|
||||
: public llvm::FunctionPass {
|
||||
typedef llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter>
|
||||
IRBuilder;
|
||||
llvm::Type* m_llvm_mask_type;
|
||||
llvm::Type* m_native_mask_type;
|
||||
llvm::Constant* m_wide_zero_initializer;
|
||||
std::unordered_map<llvm::Instruction*, llvm::Value*> m_native_mask_by_producing_inst;
|
||||
std::unordered_map<llvm::Value*, llvm::Value*> m_llvm_mask_from_livein_by_native_mask;
|
||||
std::unordered_map<llvm::Instruction*, llvm::Value*>
|
||||
m_native_mask_by_producing_inst;
|
||||
std::unordered_map<llvm::Value*, llvm::Value*>
|
||||
m_llvm_mask_from_livein_by_native_mask;
|
||||
std::vector<llvm::Instruction*> m_phiNodesWithNativeMasks;
|
||||
|
||||
public:
|
||||
@@ -57,11 +59,13 @@ public:
|
||||
, m_llvm_mask_type(nullptr)
|
||||
, m_native_mask_type(nullptr)
|
||||
, m_wide_zero_initializer(nullptr)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
bool doInitialization (llvm::Module &M) override {
|
||||
llvm::Type* llvm_type_bool = llvm::Type::getInt1Ty (M.getContext());
|
||||
llvm::Type* llvm_type_int32 = llvm::Type::getInt32Ty (M.getContext());
|
||||
bool doInitialization(llvm::Module& M) override
|
||||
{
|
||||
llvm::Type* llvm_type_bool = llvm::Type::getInt1Ty(M.getContext());
|
||||
llvm::Type* llvm_type_int32 = llvm::Type::getInt32Ty(M.getContext());
|
||||
|
||||
#if OSL_LLVM_VERSION >= 110
|
||||
m_llvm_mask_type = llvm::FixedVectorType::get(llvm_type_bool, WidthT);
|
||||
@@ -72,39 +76,45 @@ public:
|
||||
// what the native mask type should be. And if necessary maintain a
|
||||
// 16 bit and 32 bit native mask representation to be passed as a
|
||||
// livein.
|
||||
m_native_mask_type = llvm::FixedVectorType::get(llvm_type_int32, WidthT);
|
||||
# if OSL_LLVM_VERSION >= 112
|
||||
m_wide_zero_initializer = llvm::ConstantDataVector::getSplat(WidthT,
|
||||
llvm::ConstantInt::get(M.getContext(), llvm::APInt(32,0)));
|
||||
# else
|
||||
m_native_mask_type = llvm::FixedVectorType::get(llvm_type_int32,
|
||||
WidthT);
|
||||
# if OSL_LLVM_VERSION >= 112
|
||||
m_wide_zero_initializer = llvm::ConstantDataVector::getSplat(
|
||||
WidthT, llvm::ConstantInt::get(M.getContext(), llvm::APInt(32, 0)));
|
||||
# else
|
||||
m_wide_zero_initializer = llvm::ConstantVector::getSplat(
|
||||
llvm::ElementCount(WidthT, false),
|
||||
llvm::ConstantInt::get (M.getContext(), llvm::APInt(32,0)));
|
||||
# endif
|
||||
llvm::ElementCount(WidthT, false),
|
||||
llvm::ConstantInt::get(M.getContext(), llvm::APInt(32, 0)));
|
||||
# endif
|
||||
#else
|
||||
m_llvm_mask_type = llvm::VectorType::get(llvm_type_bool, WidthT);
|
||||
m_llvm_mask_type = llvm::VectorType::get(llvm_type_bool, WidthT);
|
||||
m_native_mask_type = llvm::VectorType::get(llvm_type_int32, WidthT);
|
||||
m_wide_zero_initializer = llvm::ConstantVector::getSplat(WidthT, llvm::ConstantInt::get (M.getContext(), llvm::APInt(32,0)));
|
||||
m_wide_zero_initializer = llvm::ConstantVector::getSplat(
|
||||
WidthT, llvm::ConstantInt::get(M.getContext(), llvm::APInt(32, 0)));
|
||||
#endif
|
||||
return false; // I don't think we modified the module
|
||||
return false; // I don't think we modified the module
|
||||
}
|
||||
|
||||
bool runOnFunction(llvm::Function &F) override {
|
||||
OSL_DEV_ONLY(llvm::errs() << ">>>>>>>>>>>>>>>>>>PreventBitMasksFromBeingLiveinsToBasicBlocks<" << WidthT << ">:");
|
||||
bool runOnFunction(llvm::Function& F) override
|
||||
{
|
||||
OSL_DEV_ONLY(
|
||||
llvm::errs()
|
||||
<< ">>>>>>>>>>>>>>>>>>PreventBitMasksFromBeingLiveinsToBasicBlocks<"
|
||||
<< WidthT << ">:");
|
||||
OSL_DEV_ONLY(llvm::errs().write_escaped(F.getName()) << '\n');
|
||||
|
||||
m_native_mask_by_producing_inst.clear();
|
||||
|
||||
bool changed = false;
|
||||
|
||||
for (llvm::BasicBlock &bb : F) {
|
||||
for (llvm::BasicBlock& bb : F) {
|
||||
OSL_DEV_ONLY(llvm::errs() << ">>>>>>>>>Basic Block: ");
|
||||
OSL_DEV_ONLY(llvm::errs().write_escaped(bb.getName()) << '\n');
|
||||
|
||||
m_phiNodesWithNativeMasks.clear();
|
||||
m_llvm_mask_from_livein_by_native_mask.clear();
|
||||
|
||||
for (llvm::Instruction &inst : bb) {
|
||||
for (llvm::Instruction& inst : bb) {
|
||||
// We could possibly identify all the instruction types that
|
||||
// we "think" could be using a mask, but feel just looking
|
||||
// at the operand types is cheaper.
|
||||
@@ -120,21 +130,24 @@ public:
|
||||
// back to llvm masks.
|
||||
IRBuilder builder(&bb);
|
||||
builder.SetInsertPoint(&inst);
|
||||
for (llvm::Instruction* phiNodeWithNativeMask : m_phiNodesWithNativeMasks) {
|
||||
llvm::Value* llvm_mask = builder.CreateICmpSLT (phiNodeWithNativeMask,m_wide_zero_initializer);
|
||||
for (llvm::Instruction* phiNodeWithNativeMask :
|
||||
m_phiNodesWithNativeMasks) {
|
||||
llvm::Value* llvm_mask
|
||||
= builder.CreateICmpSLT(phiNodeWithNativeMask,
|
||||
m_wide_zero_initializer);
|
||||
// Now we need to replace all uses of phiNodeWithNativeMask with our converted llvm mask
|
||||
auto use_iter = phiNodeWithNativeMask->use_begin(),
|
||||
use_end = phiNodeWithNativeMask->use_end();
|
||||
for (; use_iter != use_end;)
|
||||
{
|
||||
llvm::Use &use = *use_iter;
|
||||
use_end = phiNodeWithNativeMask->use_end();
|
||||
for (; use_iter != use_end;) {
|
||||
llvm::Use& use = *use_iter;
|
||||
++use_iter;
|
||||
auto *user = llvm::dyn_cast<llvm::Instruction>(use.getUser());
|
||||
// We need to skip the use wher the user is our conversion to a llvm_mask
|
||||
auto* user = llvm::dyn_cast<llvm::Instruction>(
|
||||
use.getUser());
|
||||
// We need to skip the use where the user is our conversion to a llvm_mask
|
||||
if (user && user == llvm_mask)
|
||||
continue;
|
||||
use.set(llvm_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_phiNodesWithNativeMasks.clear();
|
||||
@@ -151,7 +164,8 @@ public:
|
||||
bool phiNodeHadOperandReplacedInLastPassOverOperands;
|
||||
|
||||
OSL_DEV_ONLY(llvm::errs() << ">>>>Op: ");
|
||||
OSL_DEV_ONLY(llvm::errs().write_escaped(inst.getOpcodeName()) << '\n');
|
||||
OSL_DEV_ONLY(llvm::errs().write_escaped(inst.getOpcodeName())
|
||||
<< '\n');
|
||||
|
||||
// As we may have multiple operands that need to be replaced
|
||||
// for a phi node, once we discover a qualifying replacement
|
||||
@@ -167,25 +181,32 @@ public:
|
||||
|
||||
// As we could be replacing operands, but not the number of operands
|
||||
// we use index vs. iterator based loop construct
|
||||
for (unsigned operand_i = 0, num_operands = inst.getNumOperands();
|
||||
operand_i != num_operands;
|
||||
++operand_i) {
|
||||
|
||||
llvm::Value *op_val = inst.getOperand (operand_i);
|
||||
for (unsigned operand_i = 0,
|
||||
num_operands = inst.getNumOperands();
|
||||
operand_i != num_operands; ++operand_i) {
|
||||
llvm::Value* op_val = inst.getOperand(operand_i);
|
||||
if (op_val != nullptr) {
|
||||
llvm::Type* op_type = op_val->getType();
|
||||
llvm::Type* op_type = op_val->getType();
|
||||
if (op_type == m_llvm_mask_type) {
|
||||
// See if the value came from an instruction
|
||||
auto *producing_instr = llvm::dyn_cast<llvm::Instruction>(op_val);
|
||||
auto* producing_instr
|
||||
= llvm::dyn_cast<llvm::Instruction>(op_val);
|
||||
if (producing_instr != nullptr) {
|
||||
llvm::BasicBlock* producing_bb = producing_instr->getParent();
|
||||
llvm::BasicBlock* producing_bb
|
||||
= producing_instr->getParent();
|
||||
|
||||
// If a phi node needs to have one operand promoted,
|
||||
// it will need all operands promoted even if they were
|
||||
// produced in the same basic block, so the types match
|
||||
if (phiNodeHadOperandReplaced || producing_bb != &bb) {
|
||||
OSL_DEV_ONLY(llvm::errs() << "Uses llvm mask <" <<WidthT << "xi1> from different Basic Block: ");
|
||||
OSL_DEV_ONLY(llvm::errs().write_escaped(op_val->getName()) << '\n');
|
||||
if (phiNodeHadOperandReplaced
|
||||
|| producing_bb != &bb) {
|
||||
OSL_DEV_ONLY(
|
||||
llvm::errs()
|
||||
<< "Uses llvm mask <" << WidthT
|
||||
<< "xi1> from different Basic Block: ");
|
||||
OSL_DEV_ONLY(llvm::errs().write_escaped(
|
||||
op_val->getName())
|
||||
<< '\n');
|
||||
changed = true;
|
||||
|
||||
// We can't let an unrepresentable data type of <16xi1>, <8xi1> or <4xi1>
|
||||
@@ -195,37 +216,68 @@ public:
|
||||
llvm::Value* native_mask = nullptr;
|
||||
{
|
||||
// We may have already created a native mask for this instruction
|
||||
auto search_result = m_native_mask_by_producing_inst.find(producing_instr);
|
||||
if (search_result == m_native_mask_by_producing_inst.end()) {
|
||||
|
||||
auto search_result
|
||||
= m_native_mask_by_producing_inst
|
||||
.find(producing_instr);
|
||||
if (search_result
|
||||
== m_native_mask_by_producing_inst
|
||||
.end()) {
|
||||
// Scan producing basic block for an existing sign extend instruction
|
||||
// for the producing_instr. As the existence of a basic block means
|
||||
// we most likely have a branch higher up whose test required a sign extend
|
||||
for (llvm::Instruction &other_inst : *producing_bb) {
|
||||
auto *existing_sign_ext = llvm::dyn_cast<llvm::SExtInst>(&other_inst);
|
||||
for (llvm::Instruction&
|
||||
other_inst :
|
||||
*producing_bb) {
|
||||
auto* existing_sign_ext
|
||||
= llvm::dyn_cast<
|
||||
llvm::SExtInst>(
|
||||
&other_inst);
|
||||
if (existing_sign_ext) {
|
||||
OSL_ASSERT(existing_sign_ext->getNumOperands() == 1);
|
||||
llvm::Value *existing_operand = existing_sign_ext->getOperand (0);
|
||||
if (existing_operand == producing_instr) {
|
||||
OSL_ASSERT(existing_sign_ext->getType() == m_native_mask_type);
|
||||
OSL_DEV_ONLY(llvm::errs() << "Using existing sign ext in producing bb\n");
|
||||
OSL_ASSERT(
|
||||
existing_sign_ext
|
||||
->getNumOperands()
|
||||
== 1);
|
||||
llvm::Value*
|
||||
existing_operand
|
||||
= existing_sign_ext
|
||||
->getOperand(
|
||||
0);
|
||||
if (existing_operand
|
||||
== producing_instr) {
|
||||
OSL_ASSERT(
|
||||
existing_sign_ext
|
||||
->getType()
|
||||
== m_native_mask_type);
|
||||
OSL_DEV_ONLY(
|
||||
llvm::errs()
|
||||
<< "Using existing sign ext in producing bb\n");
|
||||
|
||||
native_mask = existing_sign_ext;
|
||||
native_mask
|
||||
= existing_sign_ext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nullptr == native_mask) {
|
||||
IRBuilder builder(producing_bb);
|
||||
builder.SetInsertPoint(&producing_bb->back());
|
||||
IRBuilder builder(
|
||||
producing_bb);
|
||||
builder.SetInsertPoint(
|
||||
&producing_bb->back());
|
||||
|
||||
native_mask = builder.CreateSExt(producing_instr, m_native_mask_type);
|
||||
native_mask
|
||||
= builder.CreateSExt(
|
||||
producing_instr,
|
||||
m_native_mask_type);
|
||||
// NOTE: we did add instructions, but not to the BB we are currently
|
||||
// iterating over instructions
|
||||
}
|
||||
m_native_mask_by_producing_inst.insert(std::make_pair(producing_instr,native_mask));
|
||||
m_native_mask_by_producing_inst
|
||||
.insert(std::make_pair(
|
||||
producing_instr,
|
||||
native_mask));
|
||||
} else {
|
||||
native_mask = search_result->second;
|
||||
native_mask
|
||||
= search_result->second;
|
||||
}
|
||||
}
|
||||
OSL_ASSERT(native_mask);
|
||||
@@ -239,16 +291,26 @@ public:
|
||||
llvm::Value* llvm_mask = nullptr;
|
||||
{
|
||||
// We may have already created a llvm mask in this basic block for the native mask
|
||||
auto search_result = m_llvm_mask_from_livein_by_native_mask.find(native_mask);
|
||||
if (search_result == m_llvm_mask_from_livein_by_native_mask.end()) {
|
||||
auto search_result
|
||||
= m_llvm_mask_from_livein_by_native_mask
|
||||
.find(native_mask);
|
||||
if (search_result
|
||||
== m_llvm_mask_from_livein_by_native_mask
|
||||
.end()) {
|
||||
// Insert the conversion from native to llvm mask
|
||||
// somewhere before the 1st instruction that needs to use it in this basic block
|
||||
IRBuilder builder(&bb);
|
||||
builder.SetInsertPoint(&inst);
|
||||
builder.SetInsertPoint(
|
||||
&inst);
|
||||
|
||||
llvm_mask = builder.CreateICmpSLT (native_mask,m_wide_zero_initializer);
|
||||
llvm_mask = builder.CreateICmpSLT(
|
||||
native_mask,
|
||||
m_wide_zero_initializer);
|
||||
|
||||
m_llvm_mask_from_livein_by_native_mask.insert(std::make_pair(native_mask,llvm_mask));
|
||||
m_llvm_mask_from_livein_by_native_mask
|
||||
.insert(std::make_pair(
|
||||
native_mask,
|
||||
llvm_mask));
|
||||
|
||||
// NOTE: we did add instructions to this bb,
|
||||
// but the should be inserted before the current inst.
|
||||
@@ -257,12 +319,13 @@ public:
|
||||
// iterator should not invalidate the iterator
|
||||
|
||||
} else {
|
||||
llvm_mask = search_result->second;
|
||||
llvm_mask
|
||||
= search_result->second;
|
||||
}
|
||||
}
|
||||
inst.setOperand (operand_i, llvm_mask);
|
||||
inst.setOperand(operand_i,
|
||||
llvm_mask);
|
||||
} else {
|
||||
|
||||
// Phi nodes have to exist at the top of a basic block which precludes
|
||||
// our basic algorithm from just converting the native mask back to a llvm mask
|
||||
// before the phi node.
|
||||
@@ -270,24 +333,37 @@ public:
|
||||
// and insert an instruction to convert it after the block of phi nodes
|
||||
// However, this now means we will need to find all uses of the phi node's
|
||||
// result and replace them with our converted llvm_mask
|
||||
inst.setOperand (operand_i, native_mask);
|
||||
inst.setOperand(operand_i,
|
||||
native_mask);
|
||||
phiNodeHadOperandReplaced = true;
|
||||
phiNodeHadOperandReplacedInLastPassOverOperands = true;
|
||||
phiNodeHadOperandReplacedInLastPassOverOperands
|
||||
= true;
|
||||
}
|
||||
// We should be able to continue iterating over the rest of the operands
|
||||
}
|
||||
} else if (phiNodeHadOperandReplaced) {
|
||||
auto *constant = llvm::dyn_cast<llvm::Constant>(op_val);
|
||||
auto* constant
|
||||
= llvm::dyn_cast<llvm::Constant>(
|
||||
op_val);
|
||||
if (constant) {
|
||||
OSL_DEV_ONLY(llvm::errs() << "Uses constant llvm mask <" <<WidthT << "xi1> \n");
|
||||
OSL_DEV_ONLY(
|
||||
llvm::errs()
|
||||
<< "Uses constant llvm mask <"
|
||||
<< WidthT << "xi1> \n");
|
||||
|
||||
// Should handle promoting whatever the constant value is (most likely zeroinitializer)
|
||||
llvm::ConstantFolder Folder;
|
||||
auto *signExtConstant = Folder.CreateCast(llvm::Instruction::SExt, constant, m_native_mask_type);
|
||||
auto* signExtConstant
|
||||
= Folder.CreateCast(
|
||||
llvm::Instruction::SExt,
|
||||
constant, m_native_mask_type);
|
||||
|
||||
inst.setOperand (operand_i, signExtConstant);
|
||||
inst.setOperand(operand_i,
|
||||
signExtConstant);
|
||||
} else {
|
||||
OSL_ASSERT(0 && "Unhandled/Unexpected llvm mask type");
|
||||
OSL_ASSERT(
|
||||
0
|
||||
&& "Unhandled/Unexpected llvm mask type");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,11 +397,9 @@ public:
|
||||
// including this file will need its own static members defined. LLVM will
|
||||
// assign IDs when they get registered, so this initialization value is not
|
||||
// important.
|
||||
template<>
|
||||
char PreventBitMasksFromBeingLiveinsToBasicBlocks<8>::ID = 0;
|
||||
template<> char PreventBitMasksFromBeingLiveinsToBasicBlocks<8>::ID = 0;
|
||||
|
||||
template<>
|
||||
char PreventBitMasksFromBeingLiveinsToBasicBlocks<16>::ID = 0;
|
||||
template<> char PreventBitMasksFromBeingLiveinsToBasicBlocks<16>::ID = 0;
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
|
||||
+2485
-2191
File diff suppressed because it is too large
Load Diff
@@ -2,48 +2,47 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
|
||||
#include <OpenImageIO/typedesc.h>
|
||||
#include <OpenImageIO/ustring.h>
|
||||
|
||||
#include <OpenImageIO/argparse.h>
|
||||
#include <OpenImageIO/strutil.h>
|
||||
#include <OpenImageIO/sysutil.h>
|
||||
#include <OpenImageIO/typedesc.h>
|
||||
#include <OpenImageIO/unittest.h>
|
||||
#include <OpenImageIO/ustring.h>
|
||||
|
||||
#include <OSL/llvm_util.h>
|
||||
|
||||
|
||||
typedef int (*IntFuncOfTwoInts)(int,int);
|
||||
typedef int (*IntFuncOfTwoInts)(int, int);
|
||||
|
||||
static bool verbose = false;
|
||||
static bool debug = false;
|
||||
static int memtest = 0;
|
||||
static bool debug = false;
|
||||
static int memtest = 0;
|
||||
|
||||
|
||||
|
||||
static void
|
||||
getargs (int argc, char *argv[])
|
||||
getargs(int argc, char* argv[])
|
||||
{
|
||||
bool help = false;
|
||||
OIIO::ArgParse ap;
|
||||
ap.options ("llvmutil_test\n"
|
||||
OIIO_INTRO_STRING "\n"
|
||||
"Usage: llvmutil_test [options]",
|
||||
"--help", &help, "Print help message",
|
||||
"-v", &verbose, "Verbose mode",
|
||||
"--debug", &debug, "Debug mode",
|
||||
"--memtest %d", &memtest, "Memory test mode (arg: iterations)",
|
||||
// "--iters %d", &iterations,
|
||||
// Strutil::sprintf("Number of iterations (default: %d)", iterations).c_str(),
|
||||
// "--trials %d", &ntrials, "Number of trials",
|
||||
NULL);
|
||||
if (ap.parse (argc, (const char**)argv) < 0) {
|
||||
// clang-format off
|
||||
ap.intro("llvmutil_test\n" OIIO_INTRO_STRING);
|
||||
ap.usage("llvmutil_test [options]");
|
||||
ap.arg("-v", &verbose)
|
||||
.help("Verbose output");
|
||||
ap.arg("--debug", &debug)
|
||||
.help("Debug mode");
|
||||
ap.arg("--memtest %d:ITERATIONS", &memtest)
|
||||
.help("Memory test mode");
|
||||
// clang-format on
|
||||
if (ap.parse(argc, (const char**)argv) < 0) {
|
||||
std::cerr << ap.geterror() << std::endl;
|
||||
ap.usage ();
|
||||
exit (EXIT_FAILURE);
|
||||
ap.usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (help) {
|
||||
ap.usage ();
|
||||
exit (EXIT_FAILURE);
|
||||
ap.usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,45 +52,45 @@ getargs (int argc, char *argv[])
|
||||
// function on the fly, JIT it, and call it:
|
||||
// int myadd (int arg1, int arg2)
|
||||
// {
|
||||
// return arg1 + arg2;
|
||||
// return arg1 + arg2;
|
||||
// }
|
||||
//
|
||||
void
|
||||
test_int_func ()
|
||||
test_int_func()
|
||||
{
|
||||
// Setup
|
||||
OSL::pvt::LLVM_Util::PerThreadInfo pti;
|
||||
OSL::pvt::LLVM_Util::PerThreadInfo pti;
|
||||
OSL::pvt::LLVM_Util ll(pti);
|
||||
|
||||
// Make a function with prototype: int myadd (int arg1, int arg2)
|
||||
// and make it the current function.
|
||||
auto func = ll.make_function ("myadd", // name
|
||||
false, // fastcall
|
||||
ll.type_int(), // return
|
||||
{ ll.type_int(), ll.type_int() }); // args
|
||||
ll.current_function (func);
|
||||
auto func = ll.make_function("myadd", // name
|
||||
false, // fastcall
|
||||
ll.type_int(), // return
|
||||
{ ll.type_int(), ll.type_int() }); // args
|
||||
ll.current_function(func);
|
||||
|
||||
// Generate the ops for this function: return arg1 + arg2
|
||||
llvm::Value *arg1 = ll.current_function_arg (0);
|
||||
llvm::Value *arg2 = ll.current_function_arg (1);
|
||||
llvm::Value *sum = ll.op_add (arg1, arg2);
|
||||
ll.op_return (sum);
|
||||
llvm::Value* arg1 = ll.current_function_arg(0);
|
||||
llvm::Value* arg2 = ll.current_function_arg(1);
|
||||
llvm::Value* sum = ll.op_add(arg1, arg2);
|
||||
ll.op_return(sum);
|
||||
|
||||
// Optimize it
|
||||
ll.setup_optimization_passes (0);
|
||||
ll.do_optimize ();
|
||||
ll.setup_optimization_passes(0);
|
||||
ll.do_optimize();
|
||||
|
||||
// Print the optimized bitcode
|
||||
std::cout << "Generated the following bitcode:\n"
|
||||
<< ll.bitcode_string(func) << "\n";
|
||||
|
||||
// Ask for a callable function (will JIT on demand)
|
||||
IntFuncOfTwoInts myadd = (IntFuncOfTwoInts) ll.getPointerToFunction (func);
|
||||
IntFuncOfTwoInts myadd = (IntFuncOfTwoInts)ll.getPointerToFunction(func);
|
||||
|
||||
// Call it:
|
||||
int result = myadd (13, 29);
|
||||
int result = myadd(13, 29);
|
||||
std::cout << "The result is " << result << "\n";
|
||||
OIIO_CHECK_EQUAL (result, 42);
|
||||
OIIO_CHECK_EQUAL(result, 42);
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +103,7 @@ test_int_func ()
|
||||
// }
|
||||
//
|
||||
void
|
||||
test_triple_func ()
|
||||
test_triple_func()
|
||||
{
|
||||
// Setup
|
||||
OSL::pvt::LLVM_Util::PerThreadInfo pti;
|
||||
@@ -112,29 +111,29 @@ test_triple_func ()
|
||||
|
||||
// Make a function with prototype: int myadd (int arg1, int arg2)
|
||||
// and make it the current function.
|
||||
auto func = ll.make_function ("myaddv", // name
|
||||
false, // fastcall
|
||||
ll.type_void(), // return
|
||||
{ (llvm::Type *)ll.type_triple_ptr(), // result
|
||||
(llvm::Type *)ll.type_triple_ptr(), // arg1
|
||||
ll.type_float() }); // arg2
|
||||
ll.current_function (func);
|
||||
auto func = ll.make_function("myaddv", // name
|
||||
false, // fastcall
|
||||
ll.type_void(), // return
|
||||
{ (llvm::Type*)ll.type_triple_ptr(), // result
|
||||
(llvm::Type*)ll.type_triple_ptr(), // arg1
|
||||
ll.type_float() }); // arg2
|
||||
ll.current_function(func);
|
||||
|
||||
// Generate the ops for this function: r = a*b
|
||||
llvm::Value *rptr = ll.current_function_arg (0);
|
||||
llvm::Value *aptr = ll.current_function_arg (1);
|
||||
llvm::Value *b = ll.current_function_arg (2);
|
||||
llvm::Value* rptr = ll.current_function_arg(0);
|
||||
llvm::Value* aptr = ll.current_function_arg(1);
|
||||
llvm::Value* b = ll.current_function_arg(2);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
llvm::Value *r_elptr = ll.GEP (rptr, 0, i);
|
||||
llvm::Value *a_elptr = ll.GEP (aptr, 0, i);
|
||||
llvm::Value *product = ll.op_mul (ll.op_load(a_elptr), b);
|
||||
ll.op_store (product, r_elptr);
|
||||
llvm::Value* r_elptr = ll.GEP(rptr, 0, i);
|
||||
llvm::Value* a_elptr = ll.GEP(aptr, 0, i);
|
||||
llvm::Value* product = ll.op_mul(ll.op_load(a_elptr), b);
|
||||
ll.op_store(product, r_elptr);
|
||||
}
|
||||
ll.op_return ();
|
||||
ll.op_return();
|
||||
|
||||
// Optimize it
|
||||
ll.setup_optimization_passes (0);
|
||||
ll.do_optimize ();
|
||||
ll.setup_optimization_passes(0);
|
||||
ll.do_optimize();
|
||||
|
||||
// Print the optimized bitcode
|
||||
std::cout << "Generated the following bitcode:\n"
|
||||
@@ -142,27 +141,27 @@ test_triple_func ()
|
||||
|
||||
// Ask for a callable function (will JIT on demand)
|
||||
typedef void (*FuncVecVecFloat)(void*, void*, float);
|
||||
FuncVecVecFloat f = (FuncVecVecFloat) ll.getPointerToFunction (func);
|
||||
FuncVecVecFloat f = (FuncVecVecFloat)ll.getPointerToFunction(func);
|
||||
|
||||
// Call it:
|
||||
{
|
||||
float r[3], a[3] = { 1.0, 2.0, 3.0 }, b = 42.0;
|
||||
f (r, a, b);
|
||||
std::cout << "The result is " << r[0] << ' ' << r[1] << ' ' << r[2] << "\n";
|
||||
OIIO_CHECK_EQUAL (r[0], 42.0);
|
||||
OIIO_CHECK_EQUAL (r[1], 84.0);
|
||||
OIIO_CHECK_EQUAL (r[2], 126.0);
|
||||
float r[3], a[3] = { 1.0, 2.0, 3.0 }, b = 42.0;
|
||||
f(r, a, b);
|
||||
std::cout << "The result is " << r[0] << ' ' << r[1] << ' ' << r[2]
|
||||
<< "\n";
|
||||
OIIO_CHECK_EQUAL(r[0], 42.0);
|
||||
OIIO_CHECK_EQUAL(r[1], 84.0);
|
||||
OIIO_CHECK_EQUAL(r[2], 126.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Make a crazy big function with lots of IR, having prototype:
|
||||
// int mybig (int arg1, int arg2);
|
||||
//
|
||||
IntFuncOfTwoInts
|
||||
test_big_func (bool do_print=false)
|
||||
test_big_func(bool do_print = false)
|
||||
{
|
||||
// Setup
|
||||
OSL::pvt::LLVM_Util::PerThreadInfo pti;
|
||||
@@ -170,37 +169,36 @@ test_big_func (bool do_print=false)
|
||||
|
||||
// Make a function with prototype: int myadd (int arg1, int arg2)
|
||||
// and make it the current function in the current module.
|
||||
auto func = ll.make_function ("myadd", // name
|
||||
false, // fastcall
|
||||
ll.type_int(), // return
|
||||
{ ll.type_int(), ll.type_int() }); // args
|
||||
auto func = ll.make_function("myadd", // name
|
||||
false, // fastcall
|
||||
ll.type_int(), // return
|
||||
{ ll.type_int(), ll.type_int() }); // args
|
||||
// Make it the current function and get it ready to accept IR.
|
||||
ll.current_function (func);
|
||||
ll.current_function(func);
|
||||
|
||||
// Generate the ops for this function: return arg1 + arg2
|
||||
llvm::Value *arg1 = ll.current_function_arg (0);
|
||||
llvm::Value *arg2 = ll.current_function_arg (1);
|
||||
llvm::Value *sum = ll.op_add (arg1, arg2);
|
||||
llvm::Value* arg1 = ll.current_function_arg(0);
|
||||
llvm::Value* arg2 = ll.current_function_arg(1);
|
||||
llvm::Value* sum = ll.op_add(arg1, arg2);
|
||||
// Additional useless assignments, to bloat code
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
sum = ll.op_add (arg1, arg2);
|
||||
sum = ll.op_add(arg1, arg2);
|
||||
}
|
||||
ll.op_return (sum);
|
||||
ll.op_return(sum);
|
||||
|
||||
// Print the optimized bitcode
|
||||
// if (do_print)
|
||||
// std::cout << "Generated the following bitcode:\n"
|
||||
// << ll.bitcode_string(func) << "\n";
|
||||
|
||||
ll.setup_optimization_passes (0, true /*targetHost*/);
|
||||
ll.do_optimize ();
|
||||
ll.setup_optimization_passes(0, true /*targetHost*/);
|
||||
ll.do_optimize();
|
||||
|
||||
if (do_print)
|
||||
std::cout << "After optimizing:\n"
|
||||
<< ll.bitcode_string(func) << "\n";
|
||||
std::cout << "After optimizing:\n" << ll.bitcode_string(func) << "\n";
|
||||
|
||||
// Ask for a callable function (will JIT on demand)
|
||||
IntFuncOfTwoInts myadd = (IntFuncOfTwoInts) ll.getPointerToFunction (func);
|
||||
IntFuncOfTwoInts myadd = (IntFuncOfTwoInts)ll.getPointerToFunction(func);
|
||||
|
||||
// We're done with the module now
|
||||
// ll.remove_module (module);
|
||||
@@ -229,9 +227,9 @@ test_isa_features()
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
getargs (argc, argv);
|
||||
getargs(argc, argv);
|
||||
|
||||
// This dummy object is the "owner" of the memory holding JITed code.
|
||||
// It must outlive any LLVM_Util (and its PerThreadInfo).
|
||||
@@ -245,13 +243,14 @@ main (int argc, char *argv[])
|
||||
|
||||
if (memtest) {
|
||||
for (int i = 0; i < memtest; ++i) {
|
||||
IntFuncOfTwoInts f = test_big_func (i==0);
|
||||
int r = f (42, 42);
|
||||
OIIO_CHECK_EQUAL (r, 84);
|
||||
IntFuncOfTwoInts f = test_big_func(i == 0);
|
||||
int r = f(42, 42);
|
||||
OIIO_CHECK_EQUAL(r, 84);
|
||||
}
|
||||
std::cout << "After " << memtest << " stupid functions compiled:\n";
|
||||
std::cout << " RSS memory = "
|
||||
<< OIIO::Strutil::memformat(OIIO::Sysutil::memory_used()) << "\n";
|
||||
<< OIIO::Strutil::memformat(OIIO::Sysutil::memory_used())
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
return unit_test_failures;
|
||||
|
||||
+246
-233
@@ -2,63 +2,65 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cmath> // FIXME: used by timer.h - should be included there
|
||||
#include <cstdio>
|
||||
#include <cmath> // FIXME: used by timer.h - should be included there
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "oslexec_pvt.h"
|
||||
#include "osoreader.h"
|
||||
|
||||
#include <OpenImageIO/strutil.h>
|
||||
#include <OpenImageIO/timer.h>
|
||||
#include <OpenImageIO/thread.h>
|
||||
#include <OpenImageIO/filesystem.h>
|
||||
#include <OpenImageIO/hash.h>
|
||||
#include <OpenImageIO/strutil.h>
|
||||
#include <OpenImageIO/thread.h>
|
||||
#include <OpenImageIO/timer.h>
|
||||
|
||||
|
||||
|
||||
OSL_NAMESPACE_ENTER
|
||||
|
||||
namespace pvt { // OSL::pvt
|
||||
namespace pvt { // OSL::pvt
|
||||
|
||||
|
||||
/// Custom subclass of OSOReader that provide callbacks that set all the
|
||||
/// right fields in the ShaderMaster.
|
||||
class OSOReaderToMaster final : public OSOReader
|
||||
{
|
||||
class OSOReaderToMaster final : public OSOReader {
|
||||
public:
|
||||
OSOReaderToMaster (ShadingSystemImpl &shadingsys)
|
||||
: OSOReader (&shadingsys.errhandler()), m_shadingsys (shadingsys),
|
||||
m_master (new ShaderMaster (shadingsys)),
|
||||
m_reading_instruction(false), m_errors(false)
|
||||
{ }
|
||||
virtual ~OSOReaderToMaster () { }
|
||||
virtual bool parse_file (const std::string &filename);
|
||||
virtual bool parse_memory (const std::string &oso);
|
||||
virtual void version (const char *specid, int major, int minor);
|
||||
virtual void shader (const char *shadertype, const char *name);
|
||||
virtual void symbol (SymType symtype, TypeSpec typespec, const char *name);
|
||||
virtual void symdefault (int def);
|
||||
virtual void symdefault (float def);
|
||||
virtual void symdefault (const char *def);
|
||||
OSOReaderToMaster(ShadingSystemImpl& shadingsys)
|
||||
: OSOReader(&shadingsys.errhandler())
|
||||
, m_shadingsys(shadingsys)
|
||||
, m_master(new ShaderMaster(shadingsys))
|
||||
, m_reading_instruction(false)
|
||||
, m_errors(false)
|
||||
{
|
||||
}
|
||||
virtual ~OSOReaderToMaster() {}
|
||||
virtual bool parse_file(const std::string& filename);
|
||||
virtual bool parse_memory(const std::string& oso);
|
||||
virtual void version(const char* specid, int major, int minor);
|
||||
virtual void shader(const char* shadertype, const char* name);
|
||||
virtual void symbol(SymType symtype, TypeSpec typespec, const char* name);
|
||||
virtual void symdefault(int def);
|
||||
virtual void symdefault(float def);
|
||||
virtual void symdefault(const char* def);
|
||||
virtual void parameter_done();
|
||||
virtual void hint (string_view hintstring);
|
||||
virtual void codemarker (const char *name);
|
||||
virtual void codeend ();
|
||||
virtual void instruction (int label, const char *opcode);
|
||||
virtual void instruction_arg (const char *name);
|
||||
virtual void instruction_jump (int target);
|
||||
virtual void instruction_end ();
|
||||
virtual void hint(string_view hintstring);
|
||||
virtual void codemarker(const char* name);
|
||||
virtual void codeend();
|
||||
virtual void instruction(int label, const char* opcode);
|
||||
virtual void instruction_arg(const char* name);
|
||||
virtual void instruction_jump(int target);
|
||||
virtual void instruction_end();
|
||||
|
||||
ShaderMaster::ref master () const { return m_master; }
|
||||
ShaderMaster::ref master() const { return m_master; }
|
||||
|
||||
void add_param_default (float def, size_t offset, const Symbol& sym);
|
||||
void add_param_default (int def, size_t offset, const Symbol& sym);
|
||||
void add_param_default (const char *def, size_t offset, const Symbol& sym);
|
||||
void add_param_default(float def, size_t offset, const Symbol& sym);
|
||||
void add_param_default(int def, size_t offset, const Symbol& sym);
|
||||
void add_param_default(const char* def, size_t offset, const Symbol& sym);
|
||||
|
||||
private:
|
||||
ShadingSystemImpl &m_shadingsys; ///< Reference to the shading system
|
||||
ShadingSystemImpl& m_shadingsys; ///< Reference to the shading system
|
||||
ShaderMaster::ref m_master; ///< Reference to our master
|
||||
size_t m_firstarg; ///< First argument in current op
|
||||
size_t m_nargs; ///< Number of args so far in current op
|
||||
@@ -70,41 +72,40 @@ 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,ustringHash> UstringIntMap;
|
||||
UstringIntMap m_symmap; ///< map sym name to index
|
||||
typedef std::unordered_map<ustring, int> UstringIntMap;
|
||||
UstringIntMap m_symmap; ///< map sym name to index
|
||||
};
|
||||
|
||||
|
||||
|
||||
bool
|
||||
OSOReaderToMaster::parse_file (const std::string &filename)
|
||||
OSOReaderToMaster::parse_file(const std::string& filename)
|
||||
{
|
||||
m_master->m_osofilename = filename;
|
||||
m_master->m_osofilename = filename;
|
||||
m_master->m_maincodebegin = 0;
|
||||
m_master->m_maincodeend = 0;
|
||||
m_codesection.clear ();
|
||||
m_master->m_maincodeend = 0;
|
||||
m_codesection.clear();
|
||||
m_codesym = -1;
|
||||
return OSOReader::parse_file (filename) && ! m_errors;
|
||||
return OSOReader::parse_file(filename) && !m_errors;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
OSOReaderToMaster::parse_memory (const std::string &oso)
|
||||
OSOReaderToMaster::parse_memory(const std::string& oso)
|
||||
{
|
||||
m_master->m_osofilename = "<none>";
|
||||
m_master->m_osofilename = "<none>";
|
||||
m_master->m_maincodebegin = 0;
|
||||
m_master->m_maincodeend = 0;
|
||||
m_codesection.clear ();
|
||||
m_master->m_maincodeend = 0;
|
||||
m_codesection.clear();
|
||||
m_codesym = -1;
|
||||
return OSOReader::parse_memory (oso) && ! m_errors;
|
||||
return OSOReader::parse_memory(oso) && !m_errors;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::version (const char* /*specid*/, int major, int minor)
|
||||
OSOReaderToMaster::version(const char* /*specid*/, int major, int minor)
|
||||
{
|
||||
m_oso_major = major;
|
||||
m_oso_minor = minor;
|
||||
@@ -113,55 +114,54 @@ OSOReaderToMaster::version (const char* /*specid*/, int major, int minor)
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::shader (const char *shadertype, const char *name)
|
||||
OSOReaderToMaster::shader(const char* shadertype, const char* name)
|
||||
{
|
||||
m_master->m_shadername = name; //ustring(name);
|
||||
m_master->m_shadertype = shadertype_from_name (shadertype);
|
||||
m_master->m_shadername = name; //ustring(name);
|
||||
m_master->m_shadertype = shadertype_from_name(shadertype);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::symbol (SymType symtype, TypeSpec typespec, const char *name_)
|
||||
OSOReaderToMaster::symbol(SymType symtype, TypeSpec typespec, const char* name_)
|
||||
{
|
||||
ustring name(name_);
|
||||
Symbol sym (name, typespec, symtype);
|
||||
Symbol sym(name, typespec, symtype);
|
||||
TypeDesc t = typespec.simpletype();
|
||||
int nvals = t.aggregate * (t.is_unsized_array() ? 1 : t.numelements());
|
||||
int nvals = t.aggregate * (t.is_unsized_array() ? 1 : t.numelements());
|
||||
if (sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam) {
|
||||
// Skip structs for now, they're just placeholders
|
||||
if (typespec.is_structure()) {
|
||||
}
|
||||
else if (typespec.simpletype().basetype == TypeDesc::FLOAT) {
|
||||
sym.dataoffset ((int) m_master->m_fdefaults.size());
|
||||
expand (m_master->m_fdefaults, nvals);
|
||||
} else if (typespec.simpletype().basetype == TypeDesc::FLOAT) {
|
||||
sym.dataoffset((int)m_master->m_fdefaults.size());
|
||||
expand(m_master->m_fdefaults, nvals);
|
||||
} else if (typespec.simpletype().basetype == TypeDesc::INT) {
|
||||
sym.dataoffset ((int) m_master->m_idefaults.size());
|
||||
expand (m_master->m_idefaults, nvals);
|
||||
sym.dataoffset((int)m_master->m_idefaults.size());
|
||||
expand(m_master->m_idefaults, nvals);
|
||||
} else if (typespec.simpletype().basetype == TypeDesc::STRING) {
|
||||
sym.dataoffset ((int) m_master->m_sdefaults.size());
|
||||
expand (m_master->m_sdefaults, nvals);
|
||||
sym.dataoffset((int)m_master->m_sdefaults.size());
|
||||
expand(m_master->m_sdefaults, nvals);
|
||||
} else if (typespec.is_closure_based()) {
|
||||
// Closures are pointers, so we allocate a string default taking
|
||||
// adventage of their default being NULL as well.
|
||||
sym.dataoffset ((int) m_master->m_sdefaults.size());
|
||||
expand (m_master->m_sdefaults, nvals);
|
||||
sym.dataoffset((int)m_master->m_sdefaults.size());
|
||||
expand(m_master->m_sdefaults, nvals);
|
||||
} else {
|
||||
OSL_DASSERT (0 && "unexpected type");
|
||||
OSL_DASSERT(0 && "unexpected type");
|
||||
}
|
||||
}
|
||||
if (sym.symtype() == SymTypeConst) {
|
||||
if (typespec.simpletype().basetype == TypeDesc::FLOAT) {
|
||||
sym.dataoffset ((int) m_master->m_fconsts.size());
|
||||
expand (m_master->m_fconsts, nvals);
|
||||
sym.dataoffset((int)m_master->m_fconsts.size());
|
||||
expand(m_master->m_fconsts, nvals);
|
||||
} else if (typespec.simpletype().basetype == TypeDesc::INT) {
|
||||
sym.dataoffset ((int) m_master->m_iconsts.size());
|
||||
expand (m_master->m_iconsts, nvals);
|
||||
sym.dataoffset((int)m_master->m_iconsts.size());
|
||||
expand(m_master->m_iconsts, nvals);
|
||||
} else if (typespec.simpletype().basetype == TypeDesc::STRING) {
|
||||
sym.dataoffset ((int) m_master->m_sconsts.size());
|
||||
expand (m_master->m_sconsts, nvals);
|
||||
sym.dataoffset((int)m_master->m_sconsts.size());
|
||||
expand(m_master->m_sconsts, nvals);
|
||||
} else {
|
||||
OSL_DASSERT (0 && "unexpected type");
|
||||
OSL_DASSERT(0 && "unexpected type");
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
@@ -171,8 +171,8 @@ OSOReaderToMaster::symbol (SymType symtype, TypeSpec typespec, const char *name_
|
||||
sym.dataoffset (m_shadingsys.global_heap_offset (sym.name()));
|
||||
}
|
||||
#endif
|
||||
sym.lockgeom (m_shadingsys.lockgeom_default());
|
||||
m_master->m_symbols.push_back (sym);
|
||||
sym.lockgeom(m_shadingsys.lockgeom_default());
|
||||
m_master->m_symbols.push_back(sym);
|
||||
m_symmap[name] = int(m_master->m_symbols.size()) - 1;
|
||||
// Start the index at which we add specified defaults
|
||||
m_sym_default_index = 0;
|
||||
@@ -181,54 +181,59 @@ OSOReaderToMaster::symbol (SymType symtype, TypeSpec typespec, const char *name_
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::add_param_default (float def, size_t offset, const Symbol& sym)
|
||||
OSOReaderToMaster::add_param_default(float def, size_t offset,
|
||||
const Symbol& sym)
|
||||
{
|
||||
if (sym.typespec().is_unsized_array() && offset >= m_master->m_fdefaults.size())
|
||||
m_master->m_fdefaults.push_back(def);
|
||||
else
|
||||
m_master->m_fdefaults[offset] = def;
|
||||
if (sym.typespec().is_unsized_array()
|
||||
&& offset >= m_master->m_fdefaults.size())
|
||||
m_master->m_fdefaults.push_back(def);
|
||||
else
|
||||
m_master->m_fdefaults[offset] = def;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::add_param_default (int def, size_t offset, const Symbol& sym)
|
||||
OSOReaderToMaster::add_param_default(int def, size_t offset, const Symbol& sym)
|
||||
{
|
||||
if (sym.typespec().is_unsized_array() && offset >= m_master->m_idefaults.size())
|
||||
m_master->m_idefaults.push_back(def);
|
||||
else
|
||||
m_master->m_idefaults[offset] = def;
|
||||
if (sym.typespec().is_unsized_array()
|
||||
&& offset >= m_master->m_idefaults.size())
|
||||
m_master->m_idefaults.push_back(def);
|
||||
else
|
||||
m_master->m_idefaults[offset] = def;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::add_param_default (const char *def, size_t offset, const Symbol& sym)
|
||||
OSOReaderToMaster::add_param_default(const char* def, size_t offset,
|
||||
const Symbol& sym)
|
||||
{
|
||||
if (sym.typespec().is_unsized_array() && offset >= m_master->m_sdefaults.size())
|
||||
m_master->m_sdefaults.emplace_back(def);
|
||||
else
|
||||
m_master->m_sdefaults[offset] = ustring(def);
|
||||
if (sym.typespec().is_unsized_array()
|
||||
&& offset >= m_master->m_sdefaults.size())
|
||||
m_master->m_sdefaults.emplace_back(def);
|
||||
else
|
||||
m_master->m_sdefaults[offset] = ustring(def);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::symdefault (int def)
|
||||
OSOReaderToMaster::symdefault(int def)
|
||||
{
|
||||
OSL_DASSERT (m_master->m_symbols.size() && "symdefault but no sym");
|
||||
Symbol &sym (m_master->m_symbols.back());
|
||||
OSL_DASSERT(m_master->m_symbols.size() && "symdefault but no sym");
|
||||
Symbol& sym(m_master->m_symbols.back());
|
||||
size_t offset = sym.dataoffset() + m_sym_default_index;
|
||||
++m_sym_default_index;
|
||||
|
||||
if (sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam) {
|
||||
if (sym.typespec().simpletype().basetype == TypeDesc::FLOAT)
|
||||
add_param_default ((float)def, offset, sym);
|
||||
add_param_default((float)def, offset, sym);
|
||||
else if (sym.typespec().simpletype().basetype == TypeDesc::INT)
|
||||
add_param_default (def, offset, sym);
|
||||
add_param_default(def, offset, sym);
|
||||
else {
|
||||
OSL_DASSERT_MSG (0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
OSL_DASSERT_MSG(0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
}
|
||||
} else if (sym.symtype() == SymTypeConst) {
|
||||
if (sym.typespec().simpletype().basetype == TypeDesc::FLOAT)
|
||||
@@ -236,8 +241,8 @@ OSOReaderToMaster::symdefault (int def)
|
||||
else if (sym.typespec().simpletype().basetype == TypeDesc::INT)
|
||||
m_master->m_iconsts[offset] = def;
|
||||
else {
|
||||
OSL_DASSERT_MSG (0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
OSL_DASSERT_MSG(0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,25 +250,25 @@ OSOReaderToMaster::symdefault (int def)
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::symdefault (float def)
|
||||
OSOReaderToMaster::symdefault(float def)
|
||||
{
|
||||
OSL_DASSERT (m_master->m_symbols.size() && "symdefault but no sym");
|
||||
Symbol &sym (m_master->m_symbols.back());
|
||||
OSL_DASSERT(m_master->m_symbols.size() && "symdefault but no sym");
|
||||
Symbol& sym(m_master->m_symbols.back());
|
||||
size_t offset = sym.dataoffset() + m_sym_default_index;
|
||||
++m_sym_default_index;
|
||||
if (sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam) {
|
||||
if (sym.typespec().simpletype().basetype == TypeDesc::FLOAT)
|
||||
add_param_default (def, offset, sym);
|
||||
add_param_default(def, offset, sym);
|
||||
else {
|
||||
OSL_DASSERT_MSG (0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
OSL_DASSERT_MSG(0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
}
|
||||
} else if (sym.symtype() == SymTypeConst) {
|
||||
if (sym.typespec().simpletype().basetype == TypeDesc::FLOAT)
|
||||
m_master->m_fconsts[offset] = def;
|
||||
else {
|
||||
OSL_DASSERT_MSG (0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
OSL_DASSERT_MSG(0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,25 +276,25 @@ OSOReaderToMaster::symdefault (float def)
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::symdefault (const char *def)
|
||||
OSOReaderToMaster::symdefault(const char* def)
|
||||
{
|
||||
OSL_DASSERT (m_master->m_symbols.size() && "symdefault but no sym");
|
||||
Symbol &sym (m_master->m_symbols.back());
|
||||
OSL_DASSERT(m_master->m_symbols.size() && "symdefault but no sym");
|
||||
Symbol& sym(m_master->m_symbols.back());
|
||||
size_t offset = sym.dataoffset() + m_sym_default_index;
|
||||
++m_sym_default_index;
|
||||
if (sym.symtype() == SymTypeParam || sym.symtype() == SymTypeOutputParam) {
|
||||
if (sym.typespec().simpletype().basetype == TypeDesc::STRING)
|
||||
add_param_default (def, offset, sym);
|
||||
add_param_default(def, offset, sym);
|
||||
else {
|
||||
OSL_DASSERT_MSG (0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
OSL_DASSERT_MSG(0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
}
|
||||
} else if (sym.symtype() == SymTypeConst) {
|
||||
if (sym.typespec().simpletype().basetype == TypeDesc::STRING)
|
||||
m_master->m_sconsts[offset] = ustring(def);
|
||||
else {
|
||||
OSL_DASSERT_MSG (0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
OSL_DASSERT_MSG(0, "unexpected type: %s (%s)",
|
||||
sym.typespec().c_str(), sym.name().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -297,108 +302,112 @@ OSOReaderToMaster::symdefault (const char *def)
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::parameter_done ()
|
||||
OSOReaderToMaster::parameter_done()
|
||||
{
|
||||
OSL_DASSERT (m_master->m_symbols.size() && "parameter_done but no sym");
|
||||
Symbol &sym (m_master->m_symbols.back());
|
||||
OSL_DASSERT(m_master->m_symbols.size() && "parameter_done but no sym");
|
||||
Symbol& sym(m_master->m_symbols.back());
|
||||
|
||||
// set length of unsized array parameters
|
||||
if (sym.symtype() == SymTypeParam && sym.typespec().is_unsized_array())
|
||||
sym.initializers (m_sym_default_index / sym.typespec().aggregate());
|
||||
// set length of unsized array parameters
|
||||
if (sym.symtype() == SymTypeParam && sym.typespec().is_unsized_array())
|
||||
sym.initializers(m_sym_default_index / sym.typespec().aggregate());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::hint (string_view hintstring)
|
||||
OSOReaderToMaster::hint(string_view hintstring)
|
||||
{
|
||||
string_view h (hintstring);
|
||||
string_view h(hintstring);
|
||||
|
||||
if (Strutil::parse_prefix (h, "%filename{\"")) {
|
||||
m_sourcefile = Strutil::parse_until (h, "\"");
|
||||
if (Strutil::parse_prefix(h, "%filename{\"")) {
|
||||
m_sourcefile = Strutil::parse_until(h, "\"");
|
||||
return;
|
||||
}
|
||||
if (Strutil::parse_prefix (h, "%line{")) {
|
||||
Strutil::parse_int (h, m_sourceline);
|
||||
if (Strutil::parse_prefix(h, "%line{")) {
|
||||
Strutil::parse_int(h, m_sourceline);
|
||||
return;
|
||||
}
|
||||
if (Strutil::parse_prefix (h, "%structfields{") && m_master->m_symbols.size()) {
|
||||
Symbol &sym (m_master->m_symbols.back());
|
||||
StructSpec *structspec = sym.typespec().structspec();
|
||||
if (Strutil::parse_prefix(h, "%structfields{")
|
||||
&& m_master->m_symbols.size()) {
|
||||
Symbol& sym(m_master->m_symbols.back());
|
||||
StructSpec* structspec = sym.typespec().structspec();
|
||||
if (structspec->numfields() == 0) {
|
||||
while (1) {
|
||||
std::string afield = Strutil::parse_until (h, ",}");
|
||||
Strutil::parse_char (h, ','); // skip the separator
|
||||
if (! afield.length())
|
||||
std::string afield = Strutil::parse_until(h, ",}");
|
||||
Strutil::parse_char(h, ','); // skip the separator
|
||||
if (!afield.length())
|
||||
break;
|
||||
structspec->add_field (TypeSpec(), ustring(afield));
|
||||
structspec->add_field(TypeSpec(), ustring(afield));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Strutil::parse_prefix (h, "%mystructfield{") && m_master->m_symbols.size()) {
|
||||
if (Strutil::parse_prefix(h, "%mystructfield{")
|
||||
&& m_master->m_symbols.size()) {
|
||||
int ival = -1;
|
||||
if (Strutil::parse_int (h, ival) && ival >= 0)
|
||||
m_master->m_symbols.back().fieldid (ival);
|
||||
if (Strutil::parse_int(h, ival) && ival >= 0)
|
||||
m_master->m_symbols.back().fieldid(ival);
|
||||
return;
|
||||
}
|
||||
if (Strutil::parse_prefix (h, "%read{") && m_master->m_symbols.size()) {
|
||||
Symbol &sym (m_master->m_symbols.back());
|
||||
if (Strutil::parse_prefix(h, "%read{") && m_master->m_symbols.size()) {
|
||||
Symbol& sym(m_master->m_symbols.back());
|
||||
int first, last;
|
||||
if (Strutil::parse_int (h, first) && Strutil::parse_char(h, ',')
|
||||
&& Strutil::parse_int (h, last))
|
||||
sym.set_read (first, last);
|
||||
if (Strutil::parse_int(h, first) && Strutil::parse_char(h, ',')
|
||||
&& Strutil::parse_int(h, last))
|
||||
sym.set_read(first, last);
|
||||
return;
|
||||
}
|
||||
if (Strutil::parse_prefix (h, "%write{") && m_master->m_symbols.size()) {
|
||||
Symbol &sym (m_master->m_symbols.back());
|
||||
if (Strutil::parse_prefix(h, "%write{") && m_master->m_symbols.size()) {
|
||||
Symbol& sym(m_master->m_symbols.back());
|
||||
int first, last;
|
||||
if (Strutil::parse_int (h, first) && Strutil::parse_char(h, ',')
|
||||
&& Strutil::parse_int (h, last))
|
||||
sym.set_write (first, last);
|
||||
if (Strutil::parse_int(h, first) && Strutil::parse_char(h, ',')
|
||||
&& Strutil::parse_int(h, last))
|
||||
sym.set_write(first, last);
|
||||
return;
|
||||
}
|
||||
if (Strutil::parse_prefix(h, "%argrw{") && m_master->m_ops.size()) {
|
||||
Opcode &op (m_master->m_ops.back());
|
||||
string_view str = Strutil::parse_until (h, "}");
|
||||
Strutil::parse_string (str, str, false, Strutil::DeleteQuotes);
|
||||
Opcode& op(m_master->m_ops.back());
|
||||
string_view str = Strutil::parse_until(h, "}");
|
||||
Strutil::parse_string(str, str, false, Strutil::DeleteQuotes);
|
||||
if (str.size() != m_nargs) {
|
||||
m_shadingsys.errorfmt("Parsing shader {}: malformed hint '{}' on op {} line {}",
|
||||
m_master->shadername(), hintstring,
|
||||
m_master->m_ops.back().opname(), m_sourceline);
|
||||
m_shadingsys.errorfmt(
|
||||
"Parsing shader {}: malformed hint '{}' on op {} line {}",
|
||||
m_master->shadername(), hintstring,
|
||||
m_master->m_ops.back().opname(), m_sourceline);
|
||||
m_errors = true;
|
||||
}
|
||||
for (size_t i = 0; str.size() && i < m_nargs; i++, str.remove_prefix(1)) {
|
||||
for (size_t i = 0; str.size() && i < m_nargs;
|
||||
i++, str.remove_prefix(1)) {
|
||||
char c = str.front();
|
||||
op.argwrite (i, c == 'w' || c =='W');
|
||||
op.argread (i, c == 'r' || c =='W');
|
||||
op.argwrite(i, c == 'w' || c == 'W');
|
||||
op.argread(i, c == 'r' || c == 'W');
|
||||
}
|
||||
// Fix old bug where oslc forgot to mark getmatrix last arg as write
|
||||
ustring opname = m_master->m_ops.back().opname();
|
||||
static ustring getmatrix("getmatrix");
|
||||
if (opname == getmatrix)
|
||||
m_master->m_ops.back().argwriteonly (m_nargs-1);
|
||||
m_master->m_ops.back().argwriteonly(m_nargs - 1);
|
||||
// Fix old bug where oslc forgot to mark regex results as write.
|
||||
// This was a bug prior to 1.10.
|
||||
static ustring regex_search("regex_search");
|
||||
static ustring regex_match("regex_match");
|
||||
if ((opname == regex_search || opname == regex_match) && m_nargs > 3)
|
||||
m_master->m_ops.back().argwriteonly (2);
|
||||
m_master->m_ops.back().argwriteonly(2);
|
||||
return;
|
||||
}
|
||||
if (Strutil::parse_prefix(h, "%argderivs{")) {
|
||||
while (1) {
|
||||
string_view afield = Strutil::parse_until (h, ",}");
|
||||
Strutil::parse_char (h, ','); // skip the separator
|
||||
if (! afield.length())
|
||||
string_view afield = Strutil::parse_until(h, ",}");
|
||||
Strutil::parse_char(h, ','); // skip the separator
|
||||
if (!afield.length())
|
||||
break;
|
||||
int arg = -1;
|
||||
if (Strutil::parse_int (afield, arg) && arg >= 0)
|
||||
m_master->m_ops.back().argtakesderivs (arg, true);
|
||||
if (Strutil::parse_int(afield, arg) && arg >= 0)
|
||||
m_master->m_ops.back().argtakesderivs(arg, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Strutil::parse_prefix (h, "%meta{")) {
|
||||
if (Strutil::parse_prefix(h, "%meta{")) {
|
||||
// parse type and name
|
||||
int ival = -1;
|
||||
TypeDesc type(Strutil::parse_identifier(h, "", true));
|
||||
@@ -427,17 +436,17 @@ OSOReaderToMaster::hint (string_view hintstring)
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::codemarker (const char *name)
|
||||
OSOReaderToMaster::codemarker(const char* name)
|
||||
{
|
||||
m_sourcefile.clear();
|
||||
int nextop = (int) m_master->m_ops.size();
|
||||
int nextop = (int)m_master->m_ops.size();
|
||||
|
||||
codeend (); // Mark the end spot, if we were parsing ops before
|
||||
codeend(); // Mark the end spot, if we were parsing ops before
|
||||
|
||||
m_codesection = ustring (name);
|
||||
m_codesym = m_master->findsymbol (m_codesection);
|
||||
m_codesection = ustring(name);
|
||||
m_codesym = m_master->findsymbol(m_codesection);
|
||||
if (m_codesym >= 0)
|
||||
m_master->symbol(m_codesym)->initbegin (nextop);
|
||||
m_master->symbol(m_codesym)->initbegin(nextop);
|
||||
#if 0
|
||||
std::cerr << "Read code marker " << m_codesection
|
||||
<< " at instruction " << nextop
|
||||
@@ -448,8 +457,9 @@ OSOReaderToMaster::codemarker (const char *name)
|
||||
if (m_codesection == "___main___") {
|
||||
m_master->m_maincodebegin = nextop;
|
||||
} else if (m_codesym < 0) {
|
||||
m_shadingsys.errorfmt("Parsing shader {}: don't know what to do with code section \"{}\"",
|
||||
m_master->shadername(), name);
|
||||
m_shadingsys.errorfmt(
|
||||
"Parsing shader {}: don't know what to do with code section \"{}\"",
|
||||
m_master->shadername(), name);
|
||||
m_errors = true;
|
||||
}
|
||||
}
|
||||
@@ -457,13 +467,13 @@ OSOReaderToMaster::codemarker (const char *name)
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::codeend ()
|
||||
OSOReaderToMaster::codeend()
|
||||
{
|
||||
int nextop = (int) m_master->m_ops.size();
|
||||
int nextop = (int)m_master->m_ops.size();
|
||||
if (m_codesym >= 0) {
|
||||
// If we were previously chalking up the code to init ops for a
|
||||
// symbol, mark the end.
|
||||
m_master->symbol(m_codesym)->initend (nextop);
|
||||
m_master->symbol(m_codesym)->initend(nextop);
|
||||
} else if (m_codesection == "___main___") {
|
||||
// If we were previously reading ops for the ___main___ entry
|
||||
// point, mark its end properly.
|
||||
@@ -474,21 +484,22 @@ OSOReaderToMaster::codeend ()
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::instruction (int /*label*/, const char *opcode)
|
||||
OSOReaderToMaster::instruction(int /*label*/, const char* opcode)
|
||||
{
|
||||
ustring uopcode (opcode);
|
||||
Opcode op (uopcode, m_codesection);
|
||||
m_master->m_ops.push_back (op);
|
||||
m_firstarg = m_master->m_args.size();
|
||||
m_nargs = 0;
|
||||
m_reading_instruction = true;
|
||||
const OpDescriptor *od = m_shadingsys.op_descriptor (uopcode);
|
||||
ustring uopcode(opcode);
|
||||
Opcode op(uopcode, m_codesection);
|
||||
m_master->m_ops.push_back(op);
|
||||
m_firstarg = m_master->m_args.size();
|
||||
m_nargs = 0;
|
||||
m_reading_instruction = true;
|
||||
const OpDescriptor* od = m_shadingsys.op_descriptor(uopcode);
|
||||
if (od) {
|
||||
// Replace the name in case it was aliased for compatibility
|
||||
uopcode = od->name;
|
||||
} else {
|
||||
m_shadingsys.errorfmt("Parsing shader \"{}\": instruction \"{}\" is not known. Maybe compiled with a too-new oslc?",
|
||||
m_master->shadername(), opcode);
|
||||
m_shadingsys.errorfmt(
|
||||
"Parsing shader \"{}\": instruction \"{}\" is not known. Maybe compiled with a too-new oslc?",
|
||||
m_master->shadername(), opcode);
|
||||
m_errors = true;
|
||||
}
|
||||
}
|
||||
@@ -496,12 +507,12 @@ OSOReaderToMaster::instruction (int /*label*/, const char *opcode)
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::instruction_arg (const char *name)
|
||||
OSOReaderToMaster::instruction_arg(const char* name)
|
||||
{
|
||||
ustring argname (name);
|
||||
UstringIntMap::const_iterator found = m_symmap.find (argname);
|
||||
ustring argname(name);
|
||||
UstringIntMap::const_iterator found = m_symmap.find(argname);
|
||||
if (found != m_symmap.end()) {
|
||||
m_master->m_args.push_back (found->second);
|
||||
m_master->m_args.push_back(found->second);
|
||||
++m_nargs;
|
||||
return;
|
||||
}
|
||||
@@ -513,36 +524,36 @@ OSOReaderToMaster::instruction_arg (const char *name)
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::instruction_jump (int target)
|
||||
OSOReaderToMaster::instruction_jump(int target)
|
||||
{
|
||||
m_master->m_ops.back().add_jump (target);
|
||||
m_master->m_ops.back().add_jump(target);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
OSOReaderToMaster::instruction_end ()
|
||||
OSOReaderToMaster::instruction_end()
|
||||
{
|
||||
m_master->m_ops.back().set_args (m_firstarg, m_nargs);
|
||||
m_master->m_ops.back().source (m_sourcefile, m_sourceline);
|
||||
m_master->m_ops.back().set_args(m_firstarg, m_nargs);
|
||||
m_master->m_ops.back().source(m_sourcefile, m_sourceline);
|
||||
m_reading_instruction = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ShaderMaster::ref
|
||||
ShadingSystemImpl::loadshader (string_view cname)
|
||||
ShadingSystemImpl::loadshader(string_view cname)
|
||||
{
|
||||
if (Strutil::ends_with (cname, ".oso"))
|
||||
cname.remove_suffix (4); // strip superfluous .oso
|
||||
if (! cname.size()) {
|
||||
error ("Attempt to load shader with empty name \"\".");
|
||||
if (Strutil::ends_with(cname, ".oso"))
|
||||
cname.remove_suffix(4); // strip superfluous .oso
|
||||
if (!cname.size()) {
|
||||
error("Attempt to load shader with empty name \"\".");
|
||||
return NULL;
|
||||
}
|
||||
++m_stat_shaders_requested;
|
||||
ustring name (cname);
|
||||
lock_guard guard (m_mutex); // Thread safety
|
||||
ShaderNameMap::const_iterator found = m_shader_masters.find (name);
|
||||
ustring name(cname);
|
||||
lock_guard guard(m_mutex); // Thread safety
|
||||
ShaderNameMap::const_iterator found = m_shader_masters.find(name);
|
||||
if (found != m_shader_masters.end()) {
|
||||
// if (debug())
|
||||
// infofmt("Found {} in shader_masters", name);
|
||||
@@ -551,34 +562,35 @@ ShadingSystemImpl::loadshader (string_view cname)
|
||||
}
|
||||
|
||||
// Not found in the map
|
||||
OSOReaderToMaster oso (*this);
|
||||
bool testcwd = m_searchpath_dirs.empty(); // test "." if there's no searchpath
|
||||
std::string filename = OIIO::Filesystem::searchpath_find (name.string() + ".oso",
|
||||
m_searchpath_dirs,
|
||||
testcwd);
|
||||
if (filename.empty ()) {
|
||||
OSOReaderToMaster oso(*this);
|
||||
bool testcwd
|
||||
= m_searchpath_dirs.empty(); // test "." if there's no searchpath
|
||||
std::string filename
|
||||
= OIIO::Filesystem::searchpath_find(name.string() + ".oso",
|
||||
m_searchpath_dirs, testcwd);
|
||||
if (filename.empty()) {
|
||||
errorfmt("No .oso file could be found for shader \"{}\"", name);
|
||||
return NULL;
|
||||
}
|
||||
OIIO::Timer timer;
|
||||
bool ok = oso.parse_file (filename);
|
||||
ShaderMaster::ref r = ok ? oso.master() : nullptr;
|
||||
bool ok = oso.parse_file(filename);
|
||||
ShaderMaster::ref r = ok ? oso.master() : nullptr;
|
||||
m_shader_masters[name] = r;
|
||||
double loadtime = timer();
|
||||
double loadtime = timer();
|
||||
{
|
||||
spin_lock lock (m_stat_mutex);
|
||||
spin_lock lock(m_stat_mutex);
|
||||
m_stat_master_load_time += loadtime;
|
||||
}
|
||||
if (ok) {
|
||||
++m_stat_shaders_loaded;
|
||||
infofmt("Loaded \"{}\" (took {})", filename,
|
||||
Strutil::timeintervalformat(loadtime, 2));
|
||||
OSL_DASSERT (r);
|
||||
r->resolve_syms ();
|
||||
OSL_DASSERT(r);
|
||||
r->resolve_syms();
|
||||
// if (debug()) {
|
||||
// std::string s = r->print ();
|
||||
// if (s.length())
|
||||
// infof("%s", s);
|
||||
// infofmt("{}", s);
|
||||
// }
|
||||
} else {
|
||||
errorfmt("Unable to read \"{}\"", filename);
|
||||
@@ -590,44 +602,45 @@ ShadingSystemImpl::loadshader (string_view cname)
|
||||
|
||||
|
||||
bool
|
||||
ShadingSystemImpl::LoadMemoryCompiledShader (string_view shadername,
|
||||
string_view buffer)
|
||||
ShadingSystemImpl::LoadMemoryCompiledShader(string_view shadername,
|
||||
string_view buffer)
|
||||
{
|
||||
if (! shadername.size()) {
|
||||
error ("Attempt to load shader with empty name \"\".");
|
||||
if (!shadername.size()) {
|
||||
error("Attempt to load shader with empty name \"\".");
|
||||
return false;
|
||||
}
|
||||
if (! buffer.size()) {
|
||||
errorfmt("Attempt to load shader \"{}\" with empty OSO data.", shadername);
|
||||
if (!buffer.size()) {
|
||||
errorfmt("Attempt to load shader \"{}\" with empty OSO data.",
|
||||
shadername);
|
||||
return false;
|
||||
}
|
||||
|
||||
ustring name (shadername);
|
||||
lock_guard guard (m_mutex); // Thread safety
|
||||
ShaderNameMap::const_iterator found = m_shader_masters.find (name);
|
||||
if (found != m_shader_masters.end() && ! allow_shader_replacement()) {
|
||||
ustring name(shadername);
|
||||
lock_guard guard(m_mutex); // Thread safety
|
||||
ShaderNameMap::const_iterator found = m_shader_masters.find(name);
|
||||
if (found != m_shader_masters.end() && !allow_shader_replacement()) {
|
||||
if (debug())
|
||||
infofmt("Preload shader {} already exists in shader_masters", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Not found in the map
|
||||
OSOReaderToMaster reader (*this);
|
||||
OSOReaderToMaster reader(*this);
|
||||
OIIO::Timer timer;
|
||||
bool ok = reader.parse_memory (buffer);
|
||||
ShaderMaster::ref r = ok ? reader.master() : nullptr;
|
||||
bool ok = reader.parse_memory(buffer);
|
||||
ShaderMaster::ref r = ok ? reader.master() : nullptr;
|
||||
m_shader_masters[name] = r;
|
||||
double loadtime = timer();
|
||||
double loadtime = timer();
|
||||
{
|
||||
spin_lock lock (m_stat_mutex);
|
||||
spin_lock lock(m_stat_mutex);
|
||||
m_stat_master_load_time += loadtime;
|
||||
}
|
||||
if (ok) {
|
||||
++m_stat_shaders_loaded;
|
||||
infofmt("Loaded \"{}\" (took {})", shadername,
|
||||
Strutil::timeintervalformat(loadtime, 2));
|
||||
OSL_DASSERT (r);
|
||||
r->resolve_syms ();
|
||||
OSL_DASSERT(r);
|
||||
r->resolve_syms();
|
||||
// if (debug()) {
|
||||
// std::string s = r->print ();
|
||||
// if (s.length())
|
||||
@@ -642,5 +655,5 @@ ShadingSystemImpl::LoadMemoryCompiledShader (string_view shadername,
|
||||
|
||||
|
||||
|
||||
}; // namespace pvt
|
||||
}; // namespace pvt
|
||||
OSL_NAMESPACE_EXIT
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user