From 17ea6434c973fef6851769b0d74bb96b344d1e12 Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Mon, 1 Nov 2021 12:28:23 -0600 Subject: [PATCH 01/25] bump version to v1.2.0. --- CMakeLists.txt | 2 +- gitlab/.gitlab-ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b7cc6d6..7c7db387 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) ## Establish project ## -project(openvkl VERSION 1.1.0 LANGUAGES C CXX) +project(openvkl VERSION 1.2.0 LANGUAGES C CXX) ## Add openvkl specific macros ## diff --git a/gitlab/.gitlab-ci.yml b/gitlab/.gitlab-ci.yml index 43ad9e19..fdae0c53 100644 --- a/gitlab/.gitlab-ci.yml +++ b/gitlab/.gitlab-ci.yml @@ -4,7 +4,7 @@ variables: GIT_DEPTH: "15" KW_PROJECT_NAME: openvkl - OPENVKL_RELEASE_PACKAGE_VERSION: "1.1.0" + OPENVKL_RELEASE_PACKAGE_VERSION: "1.2.0" MACOSX_DEPLOYMENT_TARGET: "10.13" stages: From d21e17f1e0f28eba17cd1c3c84fa96d3ab81cabb Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Thu, 4 Nov 2021 12:35:30 -0500 Subject: [PATCH 02/25] superbuild: update to OpenVDB 9.0.0; also update OpenVDB dependency versions. --- gitlab/.gitlab-ci.yml | 2 +- superbuild/CMakeLists.txt | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/gitlab/.gitlab-ci.yml b/gitlab/.gitlab-ci.yml index fdae0c53..7264dade 100644 --- a/gitlab/.gitlab-ci.yml +++ b/gitlab/.gitlab-ci.yml @@ -199,7 +199,7 @@ build-arch-address-sanitizer: - export CFLAGS=-fsanitize=address - export CXXFLAGS=-fsanitize=address - export LDFLAGS=-fsanitize=address - - gitlab/build.sh -D BUILD_GLFW=OFF + - gitlab/build.sh -D BUILD_GLFW=OFF -D BUILD_OPENVDB=OFF build-arch-debug: <<: *build_job_docker diff --git a/superbuild/CMakeLists.txt b/superbuild/CMakeLists.txt index f1899bdd..404fceac 100644 --- a/superbuild/CMakeLists.txt +++ b/superbuild/CMakeLists.txt @@ -227,9 +227,6 @@ if (BUILD_OPENVDB) elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.1) message(WARNING "Disabling OpenVDB support because the icc compiler version is too low (19.1 is required)") set(BUILD_OPENVDB OFF) - elseif (BUILD_TBB AND (NOT TBB_VERSION VERSION_LESS 2021)) - message(WARNING "Disabling OpenVDB support because TBB 2021 is not supported") - set(BUILD_OPENVDB OFF) else() set(ILMBASE_VERSION "2.4.1") set(ILMBASE_URL "https://github.com/AcademySoftwareFoundation/openexr/archive/v${ILMBASE_VERSION}.zip" @@ -245,29 +242,29 @@ if (BUILD_OPENVDB) CACHE STRING "SHA256 hash of the zlib archive.") include(dep_zlib) - set(BOOST_VERSION "1.72.0") + set(BOOST_VERSION "1.77.0") string(REPLACE "." "_" BOOST_FILE_BASE "${BOOST_VERSION}") set(BOOST_BASE_URL "https://boostorg.jfrog.io/artifactory/main/release/${BOOST_VERSION}/source/boost") set(_BOOST_URL "${BOOST_BASE_URL}_${BOOST_FILE_BASE}.tar.gz") - set(_BOOST_HASH "c66e88d5786f2ca4dbebb14e06b566fb642a1a6947ad8cc9091f9f445134143f") + set(_BOOST_HASH "5347464af5b14ac54bb945dc68f1dd7c56f0dad7262816b956138fc53bcc0131") set(BOOST_URL "${_BOOST_URL}" CACHE STRING "URL of the boost archive.") set(BOOST_HASH "${_BOOST_HASH}" CACHE STRING "SHA256 hash of the boost archive.") include(dep_boost) if (BUILD_BLOSC) - set(BLOSC_VERSION "1.5.0") + set(BLOSC_VERSION "1.21.1") set(BLOSC_URL "https://github.com/Blosc/c-blosc/archive/v${BLOSC_VERSION}.zip" CACHE STRING "URL of the c-BLOSC archive.") - set(BLOSC_HASH "fddd00ae717fc840c49509c367444f37bc50daea7d7d431b6c05e9570bc443a9" + set(BLOSC_HASH "abdf8ad8e5f8a876d67b38d16ff0c40c0456cdce1dcbafe58b589671ff55d31a" CACHE STRING "SHA256 hash of the c-BLOSC archive.") include(dep_blosc) endif() - set(OPENVDB_VERSION "8.1.0") + set(OPENVDB_VERSION "9.0.0") set(OPENVDB_BASE_URL "https://github.com/AcademySoftwareFoundation/openvdb/archive") set(OPENVDB_URL "${OPENVDB_BASE_URL}/v${OPENVDB_VERSION}.zip" CACHE STRING "URL of the OpenVDB archive.") - set(OPENVDB_HASH "2ede3edfc0259b6602ed0025a91b4a6118a2e1aea14c41d9e036fe5ceb539d5a" + set(OPENVDB_HASH "631443144a1d584519e83d7e883ecf52ef6dd32260bf5435324b53453d2e095a" CACHE STRING "SHA256 hash of the OpenVDB archive.") include(dep_openvdb) endif() From 067aec2c565107490372d91cb352648bf411d607 Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Thu, 4 Nov 2021 13:09:18 -0500 Subject: [PATCH 03/25] superbuild: default to TBB 2021 (both for source builds and binaries); CI updates to still validate TBB 2020. --- gitlab/.gitlab-ci.yml | 32 ++++++++++++++++---------------- superbuild/CMakeLists.txt | 10 ++++------ 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/gitlab/.gitlab-ci.yml b/gitlab/.gitlab-ci.yml index 7264dade..a92a8c02 100644 --- a/gitlab/.gitlab-ci.yml +++ b/gitlab/.gitlab-ci.yml @@ -214,11 +214,11 @@ build-arch-devel-rkdeps: - gitlab/build.sh -D RKCOMMON_VERSION=devel -D RKCOMMON_HASH="" -D EMBREE_VERSION=devel -D EMBREE_HASH="" allow_failure: true -build-arch-TBB2021: +build-arch-TBB2020: <<: *build_job_docker image: $DOCKER_REGISTRY/ospray/docker-images:arch script: - - gitlab/build.sh -D TBB_VERSION=2021.4.0 -D TBB_HASH="" + - gitlab/build.sh -D TBB_VERSION=2020.3 -D TBB_HASH="" build-macOS: <<: *base_build_job @@ -229,20 +229,20 @@ build-macOS: - osx - clang -build-macOS-TBB2021: +build-macOS-TBB2020: <<: *base_build_job stage: build script: - - gitlab/build.sh -D TBB_VERSION=2021.4.0 -D TBB_HASH="" -DBUILD_TBB_FROM_SOURCE=ON + - gitlab/build.sh -D TBB_VERSION=2020.3 -D TBB_HASH="" tags: - osx - clang -build-macOS-arm-TBB2021: +build-macOS-arm: <<: *base_build_job stage: build script: - - gitlab/build.sh -D TBB_VERSION=2021.4.0 -D TBB_HASH="" -DBUILD_TBB_FROM_SOURCE=ON + - gitlab/build.sh -DBUILD_TBB_FROM_SOURCE=ON tags: - mac-arm @@ -258,10 +258,10 @@ build-windows-msvc15: - build/install expire_in: 3 day -build-windows-msvc15-TBB2021: +build-windows-msvc15-TBB2020: stage: build script: - - gitlab\build.bat "Visual Studio 15 2017 Win64" "v141" '"-DTBB_VERSION=2021.4.0"' '"-DTBB_HASH="""' + - gitlab\build.bat "Visual Studio 15 2017 Win64" "v141" '"-DTBB_VERSION=2020.3"' '"-DTBB_HASH="""' tags: - msvc15 - win10 @@ -354,11 +354,11 @@ test-functional-arch-devel-rkdeps: - build-arch-devel-rkdeps allow_failure: true -test-functional-arch-TBB2021: +test-functional-arch-TBB2020: <<: *test_functional_job_docker image: $DOCKER_REGISTRY/ospray/docker-images:arch needs: - - build-arch-TBB2021 + - build-arch-TBB2020 test-functional-macOS: <<: *base_functional_test_job @@ -373,10 +373,10 @@ test-functional-macOS: - ./build/openvkl/build/vklTutorialISPC - ./build/openvkl/build/vklTests --durations yes -test-functional-macOS-TBB2021: +test-functional-macOS-TBB2020: <<: *base_functional_test_job needs: - - build-macOS-TBB2021 + - build-macOS-TBB2020 tags: - osx - clang @@ -386,10 +386,10 @@ test-functional-macOS-TBB2021: - ./build/openvkl/build/vklTutorialISPC - ./build/openvkl/build/vklTests --durations yes -test-functional-macOS-arm-TBB2021: +test-functional-macOS-arm: <<: *base_functional_test_job needs: - - build-macOS-arm-TBB2021 + - build-macOS-arm tags: - mac-arm script: @@ -406,12 +406,12 @@ test-functional-windows-msvc15: - msvc15 - win10 -test-functional-windows-msvc15-TBB2021: +test-functional-windows-msvc15-TBB2020: <<: *base_functional_test_job script: - gitlab\run_tests.bat needs: - - build-windows-msvc15-TBB2021 + - build-windows-msvc15-TBB2020 tags: - msvc15 - win10 diff --git a/superbuild/CMakeLists.txt b/superbuild/CMakeLists.txt index 404fceac..184015e9 100644 --- a/superbuild/CMakeLists.txt +++ b/superbuild/CMakeLists.txt @@ -116,8 +116,8 @@ endif() option(BUILD_TBB "Build Intel Threading Building Blocks or search in environment?" ON) option(BUILD_TBB_FROM_SOURCE "Build Intel Threading Building Blocks from source or use pre-built version?" OFF) if (BUILD_TBB) + set(TBB_VERSION "2021.4.0" CACHE STRING "TBB version to download") if (BUILD_TBB_FROM_SOURCE) - set(TBB_VERSION "2021.4.0" CACHE STRING "TBB version to download") if (TBB_VERSION VERSION_LESS 2021) message(FATAL_ERROR "Only TBB 2021 and later are supported when building TBB from source") endif() @@ -126,8 +126,6 @@ if (BUILD_TBB) set(_TBB_URL "https://github.com/oneapi-src/oneTBB/archive/refs/tags/${TBB_ARCHIVE}.zip") set(_TBB_HASH "08ade531be2e4e904eb6bec8e01da51eb3b0e4e86738128eb2722b95e3fcb5e6") else() - set(TBB_VERSION "2020.3" CACHE STRING "TBB version to download") - if (TBB_VERSION VERSION_LESS 2021) set(TBB_BASE_URL "https://github.com/oneapi-src/oneTBB/releases/download/v${TBB_VERSION}/tbb-${TBB_VERSION}") else() @@ -135,15 +133,15 @@ if (BUILD_TBB) endif() if (APPLE) set(_TBB_URL "${TBB_BASE_URL}-mac.tgz") - set(_TBB_HASH "456d1319e7418c761090e22be365c88e521ab11e0630250bc4addb0e6c8e1911") + set(_TBB_HASH "519d599939c41808d6b9170253b4c993b40d481f2c56b1a3cf390aea37ddb355") set(TBB_LIB_SUBDIR "") elseif(WIN32) set(_TBB_URL "${TBB_BASE_URL}-win.zip") - set(_TBB_HASH "cda37eed5209746a79c88a658f8c1bf3782f58bd9f9f6ba0da3a16624a9bfaa1") + set(_TBB_HASH "3868c557739a7a5b74c985571648c066167fd7a0a8c63bdac00a6cfeeb58037f") set(TBB_LIB_SUBDIR "intel64/vc14") else() set(_TBB_URL "${TBB_BASE_URL}-lin.tgz") - set(_TBB_HASH "bb8cddd0277605d3ee7f4e19b138c983f298d69fcbb585385b59ef7239d5ef83") + set(_TBB_HASH "f1d26b9f3741e5d573050eef2902fcd739d2913c990f4c879a310e543fc5ffd5") set(TBB_LIB_SUBDIR "intel64/gcc4.8") endif() endif() From 0d6c7ddbd547b5375406f52229febcafd74a2d50 Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Thu, 4 Nov 2021 15:06:11 -0500 Subject: [PATCH 04/25] CI: retry jobs for Gitlab infrastructure failures. --- gitlab/.gitlab-ci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gitlab/.gitlab-ci.yml b/gitlab/.gitlab-ci.yml index a92a8c02..d1770817 100644 --- a/gitlab/.gitlab-ci.yml +++ b/gitlab/.gitlab-ci.yml @@ -7,6 +7,15 @@ variables: OPENVKL_RELEASE_PACKAGE_VERSION: "1.2.0" MACOSX_DEPLOYMENT_TARGET: "10.13" +default: + retry: + max: 2 + when: + - unknown_failure + - api_failure + - runner_system_failure + - scheduler_failure + stages: - build - test From d98d15e7f13fecf4b3ed2caf649459add049d8fe Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Thu, 4 Nov 2021 15:09:14 -0500 Subject: [PATCH 05/25] CI: by default all pipelines are interruptible, except for master, release, and devel branches. --- gitlab/.gitlab-ci.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gitlab/.gitlab-ci.yml b/gitlab/.gitlab-ci.yml index d1770817..5a7635da 100644 --- a/gitlab/.gitlab-ci.yml +++ b/gitlab/.gitlab-ci.yml @@ -8,6 +8,7 @@ variables: MACOSX_DEPLOYMENT_TARGET: "10.13" default: + interruptible: true retry: max: 2 when: @@ -17,6 +18,7 @@ default: - scheduler_failure stages: + - pre - build - test - benchmark @@ -125,6 +127,22 @@ stages: variables: BENCHMARK_SUITE: ^ExampleRenderers$ +## Pre Jobs ## + +# Do not allow pipelines for master, release, or devel branches to be +# interrupted. See https://gitlab.com/gitlab-org/gitlab/-/issues/34221 +non-interruptible-pipeline: + stage: pre + interruptible: false + only: + - master + - /release/ + - devel + script: + - echo this is a non-interruptible pipeline + tags: + - docker + ## Build Jobs ## build-centos7: From ea1ed2814de54e52528d2cae955bdf9deb8e94df Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Mon, 8 Nov 2021 09:51:07 -0600 Subject: [PATCH 06/25] CI: release jobs only on master, release, and devel branches. --- gitlab/.gitlab-ci.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gitlab/.gitlab-ci.yml b/gitlab/.gitlab-ci.yml index 5a7635da..6581ad0b 100644 --- a/gitlab/.gitlab-ci.yml +++ b/gitlab/.gitlab-ci.yml @@ -88,7 +88,14 @@ stages: - ./build/openvkl/build/vklTutorialISPC - ./build/openvkl/build/vklTests --durations yes +.job_template: &master_release_devel_only + only: + - master + - /release/ + - devel + .job_template: &base_release_job + <<: *master_release_devel_only stage: release before_script: - git submodule sync @@ -96,6 +103,7 @@ stages: - git submodule update .job_template: &base_release_test_job + <<: *master_release_devel_only stage: release-test ## Job Templates: Benchmarks ## @@ -132,12 +140,9 @@ stages: # Do not allow pipelines for master, release, or devel branches to be # interrupted. See https://gitlab.com/gitlab-org/gitlab/-/issues/34221 non-interruptible-pipeline: + <<: *master_release_devel_only stage: pre interruptible: false - only: - - master - - /release/ - - devel script: - echo this is a non-interruptible pipeline tags: @@ -732,6 +737,7 @@ release-windows-test: - release-windows scan-bdba-bin: + <<: *master_release_devel_only stage: scan-binaries image: $DOCKER_REGISTRY/ospray/docker-images:centos7 tags: [docker] @@ -746,6 +752,7 @@ scan-bdba-bin: - openvkl-*.csv av: + <<: *master_release_devel_only stage: scan-binaries tags: [docker] image: $DOCKER_REGISTRY/clamav:ubuntu20.04 From 36d850c0b55c236bdcd3a24438b108f8385aa2c5 Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Wed, 8 Dec 2021 10:01:52 -0700 Subject: [PATCH 07/25] VDB inner node observer: fix bounding box computation. --- .../cpu/volume/vdb/VdbInnerNodeObserver.cpp | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/openvkl/devices/cpu/volume/vdb/VdbInnerNodeObserver.cpp b/openvkl/devices/cpu/volume/vdb/VdbInnerNodeObserver.cpp index 45b574d1..35481699 100644 --- a/openvkl/devices/cpu/volume/vdb/VdbInnerNodeObserver.cpp +++ b/openvkl/devices/cpu/volume/vdb/VdbInnerNodeObserver.cpp @@ -142,17 +142,28 @@ namespace openvkl { const vec3ui offset = totalRes * vec3ui(vx, vy, vz); const vec3i origin = grid->rootOrigin + level.origin[n] + offset; const vec3f bbMin(origin.x, origin.y, origin.z); - const vec3f bbMax = bbMin + vec3f(totalRes); - const vec3f bbMinObj = xfmPoint(grid->indexToObject, bbMin); - const vec3f bbMaxObj = xfmPoint(grid->indexToObject, bbMax); - float *node = buffer + outputIdx * numFloats; - node[0] = bbMinObj.x; - node[1] = bbMinObj.y; - node[2] = bbMinObj.z; - node[3] = bbMaxObj.x; - node[4] = bbMaxObj.y; - node[5] = bbMaxObj.z; - const size_t vrIdx = vidx * grid->numAttributes; + const vec3f bbMax = bbMin + vec3f(totalRes); + + const box3f bboxIndex(bbMin, bbMax); + box3f bboxObject = empty; + + for (int i = 0; i < 8; ++i) { + const vec3f v = + vec3f((i & 1) ? bboxIndex.upper.x : bboxIndex.lower.x, + (i & 2) ? bboxIndex.upper.y : bboxIndex.lower.y, + (i & 4) ? bboxIndex.upper.z : bboxIndex.lower.z); + + bboxObject.extend(xfmPoint(grid->indexToObject, v)); + } + + float *node = buffer + outputIdx * numFloats; + node[0] = bboxObject.lower.x; + node[1] = bboxObject.lower.y; + node[2] = bboxObject.lower.z; + node[3] = bboxObject.upper.x; + node[4] = bboxObject.upper.y; + node[5] = bboxObject.upper.z; + const size_t vrIdx = vidx * grid->numAttributes; for (uint32_t a = 0; a < grid->numAttributes; ++a) { node[6 + 2 * a] = level.valueRange[vrIdx + a].lower; node[7 + 2 * a] = level.valueRange[vrIdx + a].upper; From d4e36704d80a33618f71360f1a4aa6aa365d83ff Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Wed, 8 Dec 2021 13:54:34 -0700 Subject: [PATCH 08/25] VDB util: add commit flag (default true) to createVolume() methods, allowing apps to set additional parameters before first commit. --- utility/vdb/include/openvkl/utility/vdb/OpenVdbGrid.h | 11 ++++++----- .../include/openvkl/utility/vdb/VdbVolumeBuffers.h | 11 ++++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/utility/vdb/include/openvkl/utility/vdb/OpenVdbGrid.h b/utility/vdb/include/openvkl/utility/vdb/OpenVdbGrid.h index 64b3444a..f7e88b54 100644 --- a/utility/vdb/include/openvkl/utility/vdb/OpenVdbGrid.h +++ b/utility/vdb/include/openvkl/utility/vdb/OpenVdbGrid.h @@ -271,9 +271,11 @@ namespace openvkl { bool deferLeaves = false); /* - * To creat a VKLVolume, we simply set our parameters and commit. + * Create a VKLVolume. + * If commit is true, the volume will be committed. Otherwise, the + * application will need to commit the volume before use. */ - VKLVolume createVolume() const; + VKLVolume createVolume(bool commit = true) const; /* * Return the number of nodes in this grid. @@ -356,11 +358,10 @@ namespace openvkl { } template - inline VKLVolume OpenVdbGrid::createVolume( -) const + inline VKLVolume OpenVdbGrid::createVolume(bool commit) const { assert(buffers); - return buffers->createVolume(); + return buffers->createVolume(commit); } template diff --git a/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h b/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h index 4f2506f8..4d057b84 100644 --- a/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h +++ b/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h @@ -109,8 +109,10 @@ namespace openvkl { /* * Create a VKLVolume from these buffers. + * If commit is true, the volume will be committed. Otherwise, the + * application will need to commit the volume before use. */ - VKLVolume createVolume() const; + VKLVolume createVolume(bool commit = true) const; VKLDevice getVKLDevice() const; @@ -450,7 +452,7 @@ namespace openvkl { } } - inline VKLVolume VdbVolumeBuffers::createVolume() const + inline VKLVolume VdbVolumeBuffers::createVolume(bool commit) const { VKLVolume volume = vklNewVolume(device, "vdb"); @@ -543,7 +545,10 @@ namespace openvkl { vklSetData(volume, "node.data", dataData); vklRelease(dataData); - vklCommit(volume); + if (commit) { + vklCommit(volume); + } + return volume; } From 82fd42ed94b96b559fe25395e16f41c020fa11f3 Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Wed, 8 Dec 2021 14:18:37 -0700 Subject: [PATCH 09/25] CI: use TBB 2020.3 for centos8-module-cmake build for compatibility with downstream CI project builds. --- gitlab/.gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitlab/.gitlab-ci.yml b/gitlab/.gitlab-ci.yml index 6581ad0b..e0efcf64 100644 --- a/gitlab/.gitlab-ci.yml +++ b/gitlab/.gitlab-ci.yml @@ -189,7 +189,7 @@ build-centos8-module-cmake: script: - module use $SHARED_MODULES_PATH - module load cmake - - gitlab/build.sh -G Ninja + - gitlab/build.sh -G Ninja -D TBB_VERSION=2020.3 -D TBB_HASH="" tags: - docker - modules From 4e1f45569196c2ca993a72d416fc38db9553d7d8 Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Wed, 19 Jan 2022 14:45:51 -0700 Subject: [PATCH 10/25] add vklSetParam() API function and implementation. --- doc/api.md | 15 ++- openvkl/CMakeLists.txt | 3 +- openvkl/api/API.cpp | 12 ++- openvkl/api/Device.h | 7 +- openvkl/common/Traits.cpp | 58 +++++++++++ openvkl/common/Traits.h | 7 +- openvkl/devices/cpu/api/CPUDevice.cpp | 133 ++++++++++++++++++++++---- openvkl/devices/cpu/api/CPUDevice.h | 7 +- openvkl/include/openvkl/parameters.h | 7 +- 9 files changed, 224 insertions(+), 25 deletions(-) create mode 100644 openvkl/common/Traits.cpp diff --git a/doc/api.md b/doc/api.md index d2de287d..2ffbd27e 100644 --- a/doc/api.md +++ b/doc/api.md @@ -230,7 +230,7 @@ counting for lifetime determination. Objects are created with particular type's In general, modifiable parameters to objects are modified using `vklSet...` functions based on the type of the parameter being set. The parameter name is -passed as a string. Below are all variants of `vklSet...`. +passed as a string. Below are variants of `vklSet...`. void vklSetBool(VKLObject object, const char *name, int b); void vklSetFloat(VKLObject object, const char *name, float x); @@ -241,6 +241,19 @@ passed as a string. Below are all variants of `vklSet...`. void vklSetString(VKLObject object, const char *name, const char *s); void vklSetVoidPtr(VKLObject object, const char *name, void *v); +A more generic parameter setter is also available, which allows setting +parameters beyond the explicit types above: + + void vklSetParam(VKLObject object, + const char *name, + VKLDataType dataType, + const void *mem); + +Note that `mem` must always be a pointer _to_ the object, otherwise accidental +type casting can occur. This is especially true for pointer types +(`VKL_VOID_PTR` and `VKLObject` handles), as they will implicitly cast to `void\ +*`, but be incorrectly interpreted. + After parameters have been set, `vklCommit` must be called on the object to make them take effect. diff --git a/openvkl/CMakeLists.txt b/openvkl/CMakeLists.txt index 01c35eda..ba167cf6 100644 --- a/openvkl/CMakeLists.txt +++ b/openvkl/CMakeLists.txt @@ -1,4 +1,4 @@ -## Copyright 2019-2021 Intel Corporation +## Copyright 2019-2022 Intel Corporation ## SPDX-License-Identifier: Apache-2.0 include(openvkl_ispc) @@ -18,6 +18,7 @@ openvkl_add_library_ispc(${PROJECT_NAME} SHARED common/ispc_util.ispc common/logging.cpp common/ManagedObject.cpp + common/Traits.cpp common/VKLCommon.cpp ${DEF_FILE} diff --git a/openvkl/api/API.cpp b/openvkl/api/API.cpp index 2594ea22..f59f3879 100644 --- a/openvkl/api/API.cpp +++ b/openvkl/api/API.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Intel Corporation +// Copyright 2019-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "../common/IteratorBase.h" @@ -663,6 +663,16 @@ extern "C" void vklSetVoidPtr(VKLObject object, const char *name, void *v) } OPENVKL_CATCH_END() +extern "C" void vklSetParam(VKLObject object, + const char *name, + VKLDataType dataType, + const void *mem) OPENVKL_CATCH_BEGIN_SAFE(object) +{ + THROW_IF_NULL(name); + deviceObj->setObjectParam(object, name, dataType, mem); +} +OPENVKL_CATCH_END() + /////////////////////////////////////////////////////////////////////////////// // Sampler //////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// diff --git a/openvkl/api/Device.h b/openvkl/api/Device.h index cd5b19a3..0ed86aaa 100644 --- a/openvkl/api/Device.h +++ b/openvkl/api/Device.h @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Intel Corporation +// Copyright 2019-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -223,6 +223,11 @@ namespace openvkl { const std::string &s) = 0; virtual void setVoidPtr(VKLObject object, const char *name, void *v) = 0; + virtual void setObjectParam(VKLObject object, + const char *name, + VKLDataType dataType, + const void *mem) = 0; + ///////////////////////////////////////////////////////////////////////// // Sampler ////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// diff --git a/openvkl/common/Traits.cpp b/openvkl/common/Traits.cpp new file mode 100644 index 00000000..298255b4 --- /dev/null +++ b/openvkl/common/Traits.cpp @@ -0,0 +1,58 @@ +// Copyright 2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "Traits.h" + +namespace openvkl { + VKLTYPEFOR_DEFINITION(VKLDevice); + VKLTYPEFOR_DEFINITION(void *); + VKLTYPEFOR_DEFINITION(bool); + VKLTYPEFOR_DEFINITION(VKLObject); + VKLTYPEFOR_DEFINITION(openvkl::ManagedObject *); + VKLTYPEFOR_DEFINITION(VKLData); + VKLTYPEFOR_DEFINITION(openvkl::Data *); + VKLTYPEFOR_DEFINITION(VKLVolume); + VKLTYPEFOR_DEFINITION(char *); + VKLTYPEFOR_DEFINITION(const char *); + VKLTYPEFOR_DEFINITION(const char[]); + VKLTYPEFOR_DEFINITION(char); + VKLTYPEFOR_DEFINITION(unsigned char); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec2uc); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec3uc); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec4uc); + VKLTYPEFOR_DEFINITION(short); + VKLTYPEFOR_DEFINITION(unsigned short); + VKLTYPEFOR_DEFINITION(int32_t); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec2i); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec3i); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec4i); + VKLTYPEFOR_DEFINITION(uint32_t); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec2ui); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec3ui); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec4ui); + VKLTYPEFOR_DEFINITION(int64_t); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec2l); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec3l); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec4l); + VKLTYPEFOR_DEFINITION(uint64_t); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec2ul); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec3ul); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec4ul); + VKLTYPEFOR_DEFINITION(float); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec2f); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec3f); + VKLTYPEFOR_DEFINITION(rkcommon::math::vec4f); + VKLTYPEFOR_DEFINITION(double); + VKLTYPEFOR_DEFINITION(rkcommon::math::box1i); + VKLTYPEFOR_DEFINITION(rkcommon::math::box2i); + VKLTYPEFOR_DEFINITION(rkcommon::math::box3i); + VKLTYPEFOR_DEFINITION(rkcommon::math::box4i); + VKLTYPEFOR_DEFINITION(rkcommon::math::box1f); + VKLTYPEFOR_DEFINITION(rkcommon::math::box2f); + VKLTYPEFOR_DEFINITION(rkcommon::math::box3f); + VKLTYPEFOR_DEFINITION(rkcommon::math::box4f); + VKLTYPEFOR_DEFINITION(rkcommon::math::linear2f); + VKLTYPEFOR_DEFINITION(rkcommon::math::linear3f); + VKLTYPEFOR_DEFINITION(rkcommon::math::affine2f); + VKLTYPEFOR_DEFINITION(rkcommon::math::affine3f); +} diff --git a/openvkl/common/Traits.h b/openvkl/common/Traits.h index 3f7222b0..5a65f038 100644 --- a/openvkl/common/Traits.h +++ b/openvkl/common/Traits.h @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Intel Corporation +// Copyright 2020-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -12,6 +12,7 @@ namespace openvkl { struct Data; + struct ManagedObject; // Public wide types for given widths template @@ -134,6 +135,7 @@ namespace openvkl { VKLTYPEFOR_SPECIALIZATION(void *, VKL_VOID_PTR); VKLTYPEFOR_SPECIALIZATION(bool, VKL_BOOL); VKLTYPEFOR_SPECIALIZATION(VKLObject, VKL_OBJECT); + VKLTYPEFOR_SPECIALIZATION(openvkl::ManagedObject *, VKL_OBJECT); VKLTYPEFOR_SPECIALIZATION(VKLData, VKL_DATA); VKLTYPEFOR_SPECIALIZATION(openvkl::Data *, VKL_DATA); VKLTYPEFOR_SPECIALIZATION(VKLVolume, VKL_VOLUME); @@ -181,4 +183,7 @@ namespace openvkl { VKLTYPEFOR_SPECIALIZATION(rkcommon::math::affine2f, VKL_AFFINE2F); VKLTYPEFOR_SPECIALIZATION(rkcommon::math::affine3f, VKL_AFFINE3F); +#define VKLTYPEFOR_DEFINITION(type) \ + constexpr VKLDataType VKLTypeFor::value + } // namespace openvkl diff --git a/openvkl/devices/cpu/api/CPUDevice.cpp b/openvkl/devices/cpu/api/CPUDevice.cpp index 04666698..0db83fe8 100644 --- a/openvkl/devices/cpu/api/CPUDevice.cpp +++ b/openvkl/devices/cpu/api/CPUDevice.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Intel Corporation +// Copyright 2019-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "CPUDevice.h" @@ -13,6 +13,98 @@ namespace openvkl { namespace cpu_device { + /////////////////////////////////////////////////////////////////////////// + // Parameter setting helpers ////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + using SetParamFcn = void(VKLObject, const char *, const void *); + + template + static void setParamOnObject(VKLObject _obj, const char *p, const T &v) + { + auto *obj = (ManagedObject *)_obj; + obj->setParam(p, v); + } + +#define declare_param_setter(TYPE) \ + { \ + VKLTypeFor::value, [](VKLObject o, const char *p, const void *v) { \ + setParamOnObject(o, p, *(TYPE *)v); \ + } \ + } + +#define declare_param_setter_object(TYPE) \ + { \ + VKLTypeFor::value, [](VKLObject o, const char *p, const void *v) { \ + ManagedObject *obj = *(TYPE *)v; \ + setParamOnObject(o, p, obj); \ + } \ + } + +#define declare_param_setter_string(TYPE) \ + { \ + VKLTypeFor::value, [](VKLObject o, const char *p, const void *v) { \ + const char *str = (const char *)v; \ + setParamOnObject(o, p, std::string(str)); \ + } \ + } + + static std::map> setParamFcns = { + declare_param_setter(void *), + declare_param_setter(bool), + declare_param_setter_object(openvkl::ManagedObject *), + declare_param_setter_object(openvkl::Data *), + declare_param_setter_string(char *), + declare_param_setter_string(const char *), + declare_param_setter_string(const char[]), + declare_param_setter(char), + declare_param_setter(unsigned char), + declare_param_setter(rkcommon::math::vec2uc), + declare_param_setter(rkcommon::math::vec3uc), + declare_param_setter(rkcommon::math::vec4uc), + declare_param_setter(short), + declare_param_setter(unsigned short), + declare_param_setter(int32_t), + declare_param_setter(rkcommon::math::vec2i), + declare_param_setter(rkcommon::math::vec3i), + declare_param_setter(rkcommon::math::vec4i), + declare_param_setter(uint32_t), + declare_param_setter(rkcommon::math::vec2ui), + declare_param_setter(rkcommon::math::vec3ui), + declare_param_setter(rkcommon::math::vec4ui), + declare_param_setter(int64_t), + declare_param_setter(rkcommon::math::vec2l), + declare_param_setter(rkcommon::math::vec3l), + declare_param_setter(rkcommon::math::vec4l), + declare_param_setter(uint64_t), + declare_param_setter(rkcommon::math::vec2ul), + declare_param_setter(rkcommon::math::vec3ul), + declare_param_setter(rkcommon::math::vec4ul), + declare_param_setter(float), + declare_param_setter(rkcommon::math::vec2f), + declare_param_setter(rkcommon::math::vec3f), + declare_param_setter(rkcommon::math::vec4f), + declare_param_setter(double), + declare_param_setter(rkcommon::math::box1i), + declare_param_setter(rkcommon::math::box2i), + declare_param_setter(rkcommon::math::box3i), + declare_param_setter(rkcommon::math::box4i), + declare_param_setter(rkcommon::math::box1f), + declare_param_setter(rkcommon::math::box2f), + declare_param_setter(rkcommon::math::box3f), + declare_param_setter(rkcommon::math::box4f), + declare_param_setter(rkcommon::math::linear2f), + declare_param_setter(rkcommon::math::linear3f), + declare_param_setter(rkcommon::math::affine2f), + declare_param_setter(rkcommon::math::affine3f), + }; + +#undef declare_param_setter + + /////////////////////////////////////////////////////////////////////////// + // CPUDevice ////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + template bool CPUDevice::supportsWidth(int width) { @@ -150,22 +242,19 @@ namespace openvkl { template void CPUDevice::setBool(VKLObject object, const char *name, const bool b) { - ManagedObject *managedObject = (ManagedObject *)object; - managedObject->setParam(name, b); + setObjectParam(object, name, VKL_BOOL, &b); } template void CPUDevice::set1f(VKLObject object, const char *name, const float x) { - ManagedObject *managedObject = (ManagedObject *)object; - managedObject->setParam(name, x); + setObjectParam(object, name, VKL_FLOAT, &x); } template void CPUDevice::set1i(VKLObject object, const char *name, const int x) { - ManagedObject *managedObject = (ManagedObject *)object; - managedObject->setParam(name, x); + setObjectParam(object, name, VKL_INT, &x); } template @@ -173,8 +262,7 @@ namespace openvkl { const char *name, const vec3f &v) { - ManagedObject *managedObject = (ManagedObject *)object; - managedObject->setParam(name, v); + setObjectParam(object, name, VKL_VEC3F, &v); } template @@ -182,8 +270,7 @@ namespace openvkl { const char *name, const vec3i &v) { - ManagedObject *managedObject = (ManagedObject *)object; - managedObject->setParam(name, v); + setObjectParam(object, name, VKL_VEC3I, &v); } template @@ -191,9 +278,7 @@ namespace openvkl { const char *name, VKLObject setObject) { - ManagedObject *target = (ManagedObject *)object; - ManagedObject *value = (ManagedObject *)setObject; - target->setParam(name, value); + setObjectParam(object, name, VKL_OBJECT, &setObject); } template @@ -201,15 +286,27 @@ namespace openvkl { const char *name, const std::string &s) { - ManagedObject *managedObject = (ManagedObject *)object; - managedObject->setParam(name, s); + setObjectParam(object, name, VKL_STRING, s.c_str()); } template void CPUDevice::setVoidPtr(VKLObject object, const char *name, void *v) { - ManagedObject *managedObject = (ManagedObject *)object; - managedObject->setParam(name, v); + setObjectParam(object, name, VKL_VOID_PTR, &v); + } + + template + void CPUDevice::setObjectParam(VKLObject object, + const char *name, + VKLDataType dataType, + const void *mem) + { + if (!setParamFcns.count(dataType)) { + throw std::runtime_error("cannot set parameter " + std::string(name) + + " for given data type"); + } + + setParamFcns[dataType](object, name, mem); } /////////////////////////////////////////////////////////////////////////// diff --git a/openvkl/devices/cpu/api/CPUDevice.h b/openvkl/devices/cpu/api/CPUDevice.h index d67a5854..b84f35c4 100644 --- a/openvkl/devices/cpu/api/CPUDevice.h +++ b/openvkl/devices/cpu/api/CPUDevice.h @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Intel Corporation +// Copyright 2019-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -323,6 +323,11 @@ namespace openvkl { const std::string &s) override; void setVoidPtr(VKLObject object, const char *name, void *v) override; + void setObjectParam(VKLObject object, + const char *name, + VKLDataType dataType, + const void *mem) override; + ///////////////////////////////////////////////////////////////////////// // Sampler ////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// diff --git a/openvkl/include/openvkl/parameters.h b/openvkl/include/openvkl/parameters.h index 00d72557..9cfd6b53 100644 --- a/openvkl/include/openvkl/parameters.h +++ b/openvkl/include/openvkl/parameters.h @@ -1,4 +1,4 @@ -// Copyright 2019 Intel Corporation +// Copyright 2019-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -18,6 +18,11 @@ OPENVKL_INTERFACE void vklSetData(VKLObject object, const char *name, VKLData da OPENVKL_INTERFACE void vklSetString(VKLObject object, const char *name, const char *s); OPENVKL_INTERFACE void vklSetVoidPtr(VKLObject object, const char *name, void *v); +OPENVKL_INTERFACE void vklSetParam(VKLObject object, + const char *name, + VKLDataType dataType, + const void *mem); + #ifdef __cplusplus } // extern "C" #endif From dea84d98a1dc97fa9cd3e5ba66a951ee8cf9624c Mon Sep 17 00:00:00 2001 From: Will Usher Date: Tue, 25 Jan 2022 14:12:58 -0800 Subject: [PATCH 11/25] Add support for IntelLLVM DPCPP compiler, takes clang style options --- cmake/openvkl_macros.cmake | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cmake/openvkl_macros.cmake b/cmake/openvkl_macros.cmake index 896ba5ff..31bf2ddc 100644 --- a/cmake/openvkl_macros.cmake +++ b/cmake/openvkl_macros.cmake @@ -1,4 +1,4 @@ -## Copyright 2019-2021 Intel Corporation +## Copyright 2019-2022 Intel Corporation ## SPDX-License-Identifier: Apache-2.0 macro(openvkl_add_library_ispc name type) @@ -51,7 +51,8 @@ endmacro() macro(openvkl_configure_global_build_flags) if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR - CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR + CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing") @@ -96,7 +97,8 @@ function(openvkl_get_compile_options_for_width WIDTH FLAGS) if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR - CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR + CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") message(STATUS "detected Clang or GNU compiler") From 0766e9af623506923d45eb9db85247e78673832c Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Wed, 15 Dec 2021 15:22:21 -0600 Subject: [PATCH 12/25] VDB volumes: add indexClippingBounds parameter, and use for vdb util's .vdb file importing to support active voxel bounding box. --- doc/api.md | 8 ++++++++ openvkl/devices/cpu/volume/vdb/VdbVolume.cpp | 12 ++++++++++- .../include/openvkl/utility/vdb/OpenVdbGrid.h | 20 ++++++++++++++++++- .../openvkl/utility/vdb/VdbVolumeBuffers.h | 16 ++++++++++++++- 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/doc/api.md b/doc/api.md index 2ffbd27e..e9d5651f 100644 --- a/doc/api.md +++ b/doc/api.md @@ -911,6 +911,14 @@ following parameters: float[] background `VKL_BACKGROUND_UNDEFINED` For each attribute, the value that is returned when sampling an undefined region outside the volume domain. + + box3i indexClippingBounds Clips the volume to the specified + index-space bounding box. This is + useful for volumes with dimensions that + are not even multiples of the leaf node + dimensions, or .vdb files with + restrictive active voxel bounding + boxes. ------------ ------------------------------------- ------------------------------ --------------------------------------- : Configuration parameters for VDB (`"vdb"`) volumes. diff --git a/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp b/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp index 19d6603a..cd325f39 100644 --- a/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp +++ b/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Intel Corporation +// Copyright 2019-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "VdbVolume.h" @@ -743,6 +743,16 @@ namespace openvkl { grid->activeSize = bbox.upper - grid->rootOrigin; indexBoundingBox = box3f(bbox); + + // support an index-space clipping bounding box, which may clip + // portions of leaf nodes; this is primarily used for .vdb volumes + // with a restrictive active voxel bounding box + const box3i indexBoundingBoxI = + this->template getParam("indexClippingBounds", empty); + + if (!indexBoundingBoxI.empty()) { + indexBoundingBox = box3f(indexBoundingBoxI); + } } // The domain-space bounding box. diff --git a/utility/vdb/include/openvkl/utility/vdb/OpenVdbGrid.h b/utility/vdb/include/openvkl/utility/vdb/OpenVdbGrid.h index f7e88b54..c2f33056 100644 --- a/utility/vdb/include/openvkl/utility/vdb/OpenVdbGrid.h +++ b/utility/vdb/include/openvkl/utility/vdb/OpenVdbGrid.h @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Intel Corporation +// Copyright 2020-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -304,6 +304,7 @@ namespace openvkl { private: void loadTransform(); + void loadActiveVoxelsBoundingBox(); void loadDeferredAt(size_t i); void loadFromGrid(typename openvdbNativeGrid::Ptr vdb, bool deferLeaves = false); @@ -460,6 +461,21 @@ namespace openvkl { i2o[14]); } + template + inline void OpenVdbGrid::loadActiveVoxelsBoundingBox() + { + assert(grid); + const auto &activeVoxelBoundingBox = grid->evalActiveVoxelBoundingBox(); + + buffers->setActiveVoxelsBoundingBox( + box3i(vec3i(activeVoxelBoundingBox.min().x(), + activeVoxelBoundingBox.min().y(), + activeVoxelBoundingBox.min().z()), + vec3i(activeVoxelBoundingBox.max().x(), + activeVoxelBoundingBox.max().y(), + activeVoxelBoundingBox.max().z()))); + } + template inline void OpenVdbGrid::loadDeferredAt(size_t i) { @@ -488,6 +504,8 @@ namespace openvkl { loadTransform(); + loadActiveVoxelsBoundingBox(); + const auto &root = vdb->tree().root(); for (auto it = root.cbeginChildOn(); it; ++it) Builder::visit( diff --git a/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h b/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h index 4d057b84..95df55ad 100644 --- a/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h +++ b/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Intel Corporation +// Copyright 2020-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -53,6 +53,8 @@ namespace openvkl { float p1, float p2); + void setActiveVoxelsBoundingBox(const box3i &bbox); + size_t numNodes() const; /* @@ -133,6 +135,8 @@ namespace openvkl { float indexToObject[12] = { 1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f}; + box3i activeVoxelsBoundingBox = empty; + /* * Level must be a number in [1, VKL_VDB_NUM_LEVELS-1]. * The level also influences the node resolution. Constant @@ -215,6 +219,11 @@ namespace openvkl { indexToObject[11] = p2; } + inline void VdbVolumeBuffers::setActiveVoxelsBoundingBox(const box3i &bbox) + { + activeVoxelsBoundingBox = bbox; + } + inline size_t VdbVolumeBuffers::numNodes() const { return level.size(); @@ -461,6 +470,11 @@ namespace openvkl { vklSetData(volume, "indexToObject", transformData); vklRelease(transformData); + if (!activeVoxelsBoundingBox.empty()) { + vklSetParam( + volume, "indexClippingBounds", VKL_BOX3I, &activeVoxelsBoundingBox); + } + // Create the data buffer from our pointers. const size_t numNodes = level.size(); From 1a8b3c0cb5d698879a655cf24cb4318b8c7b267c Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Tue, 25 Jan 2022 10:50:05 -0700 Subject: [PATCH 13/25] superbuild: move to ISPC v1.17.0. --- superbuild/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/superbuild/CMakeLists.txt b/superbuild/CMakeLists.txt index 184015e9..f1624d12 100644 --- a/superbuild/CMakeLists.txt +++ b/superbuild/CMakeLists.txt @@ -1,4 +1,4 @@ -## Copyright 2019-2021 Intel Corporation +## Copyright 2019-2022 Intel Corporation ## SPDX-License-Identifier: Apache-2.0 ## Global settings ## @@ -95,17 +95,17 @@ option(BUILD_OPENVKL_BENCHMARKS option(BUILD_ISPC "Build the Intel SPMD Program Compiler or search in environment?" ON) if (BUILD_ISPC) - set(ISPC_VERSION "1.16.1") + set(ISPC_VERSION "1.17.0") set(ISPC_BASE_URL "https://github.com/ispc/ispc/releases/download/v${ISPC_VERSION}") if (APPLE) set(_ISPC_URL "${ISPC_BASE_URL}/ispc-v${ISPC_VERSION}-macOS.tar.gz") - set(_ISPC_HASH "7dbce602d97227a9603aabfae6dc3b3aa24d1cd44f0ccfb5ae47ecd4d68e988e") + set(_ISPC_HASH "e7fdcdbd5c272955249148c452ccd7295d7cf77b35ca1dec377e72b49c847bff") elseif(WIN32) set(_ISPC_URL "${ISPC_BASE_URL}/ispc-v${ISPC_VERSION}-windows.zip") - set(_ISPC_HASH "b34de2c36aff2afaa56b669ea41f9e614a045564ca74fc0b138e17ccea4880b7") + set(_ISPC_HASH "e9a7cc98f69357482985bcbf69fa006632cee7b3606069b4d5e16dc62092d660") else() set(_ISPC_URL "${ISPC_BASE_URL}/ispc-v${ISPC_VERSION}-linux.tar.gz") - set(_ISPC_HASH "88db3d0461147c10ed81053a561ec87d3e14265227c03318f4fcaaadc831037f") + set(_ISPC_HASH "1ddd189e6b679ab269f8580fef4dd0143862c4e503d35c52d63c71721877f2ce") endif() set(ISPC_URL "${_ISPC_URL}" CACHE STRING "URL of the ISPC archive.") set(ISPC_HASH "${_ISPC_HASH}" CACHE STRING "SHA256 hash of the ISPC archive.") From 34cfddeccd9d5b507f49070e2422ae2a6f196520 Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Mon, 24 Jan 2022 16:11:31 -0700 Subject: [PATCH 14/25] particle volumes: support zero-radius particles; add corresponding functional tests. --- .../cpu/volume/particle/ParticleVolume.h | 20 ++- .../cpu/volume/particle/ParticleVolume.ispc | 7 +- testing/apps/CMakeLists.txt | 3 +- testing/apps/tests/particle_volume_radius.cpp | 130 ++++++++++++++++++ 4 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 testing/apps/tests/particle_volume_radius.cpp diff --git a/openvkl/devices/cpu/volume/particle/ParticleVolume.h b/openvkl/devices/cpu/volume/particle/ParticleVolume.h index 313b0390..40be522d 100644 --- a/openvkl/devices/cpu/volume/particle/ParticleVolume.h +++ b/openvkl/devices/cpu/volume/particle/ParticleVolume.h @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Intel Corporation +// Copyright 2020-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -23,9 +23,21 @@ namespace openvkl { static_assert(sizeof(ParticleLeafNode) == sizeof(LeafNode), "ParticleLeafNode incompatible with LeafNode"); - nominalLength.x = -radius; - nominalLength.y = radius; - nominalLength.z = radius; + if (radius < 0.f) { + throw std::runtime_error("particle radii must all be >= 0"); + } else if (radius == 0.f) { + // we require non-zero nominal lengths; note however this is only used + // in BVH construction / traversal; actual sampling will not consider + // this epsilon + const float epsilon = std::numeric_limits::min(); + nominalLength.x = -epsilon; + nominalLength.y = epsilon; + nominalLength.z = epsilon; + } else { + nominalLength.x = -radius; + nominalLength.y = radius; + nominalLength.z = radius; + } // note that valueRange will be set separately in computeValueRanges() } diff --git a/openvkl/devices/cpu/volume/particle/ParticleVolume.ispc b/openvkl/devices/cpu/volume/particle/ParticleVolume.ispc index 9bbc17d4..11d7487b 100644 --- a/openvkl/devices/cpu/volume/particle/ParticleVolume.ispc +++ b/openvkl/devices/cpu/volume/particle/ParticleVolume.ispc @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Intel Corporation +// Copyright 2020-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "../../common/export_util.h" @@ -22,7 +22,10 @@ inline void getParticleContributionGaussian(const VKLParticleVolume *uniform delta = objectCoordinates - position; - if (length(delta) > radius * self->radiusSupportFactor) { + if (radius == 0.f) { + value = length(delta) == 0.f ? w : 0.f; + return; + } else if (length(delta) > radius * self->radiusSupportFactor) { value = 0.f; return; } diff --git a/testing/apps/CMakeLists.txt b/testing/apps/CMakeLists.txt index 2a92de3d..1f777571 100644 --- a/testing/apps/CMakeLists.txt +++ b/testing/apps/CMakeLists.txt @@ -1,4 +1,4 @@ -## Copyright 2019-2021 Intel Corporation +## Copyright 2019-2022 Intel Corporation ## SPDX-License-Identifier: Apache-2.0 # Benchmarks @@ -140,6 +140,7 @@ if (BUILD_TESTING) tests/particle_volume_sampling.cpp tests/particle_volume_gradients.cpp tests/particle_volume_value_range.cpp + tests/particle_volume_radius.cpp tests/particle_volume_interval_iterator.cpp tests/multi_device.cpp ) diff --git a/testing/apps/tests/particle_volume_radius.cpp b/testing/apps/tests/particle_volume_radius.cpp new file mode 100644 index 00000000..8f646402 --- /dev/null +++ b/testing/apps/tests/particle_volume_radius.cpp @@ -0,0 +1,130 @@ +// Copyright 2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "../../external/catch.hpp" +#include "openvkl_testing.h" +#include "sampling_utility.h" + +using namespace rkcommon; +using namespace openvkl::testing; + +// verifies sampling at particle center yields the particle weight +static void sampling_at_particle_centers(VKLVolume vklVolume, + const std::vector particles) +{ + VKLSampler vklSampler = vklNewSampler(vklVolume); + vklCommit(vklSampler); + + for (size_t i = 0; i < particles.size(); i++) { + const vec4f &p = particles[i]; + + const vkl_vec3f p3{p.x, p.y, p.z}; + + INFO("particle i = " << i << ", p = " << p.x << " " << p.y << " " << p.z + << ", radius = " << p.w) + + const float referenceValue = 1.f; + + const float sampledValue = vklComputeSample(vklSampler, &p3); + INFO("sampled = " << sampledValue) + + REQUIRE(referenceValue == sampledValue); + } + + vklRelease(vklSampler); +} + +// verifies that sampling outside of the particle center yields zero +static void sampling_at_particle_centers_delta( + VKLVolume vklVolume, const std::vector particles) +{ + VKLSampler vklSampler = vklNewSampler(vklVolume); + vklCommit(vklSampler); + + const float epsilon = 1e-6f; + + for (size_t i = 0; i < particles.size(); i++) { + const vec4f &p = particles[i]; + + const vkl_vec3f p3{p.x + epsilon, p.y + epsilon, p.z + epsilon}; + + INFO("particle i = " << i << ", p = " << p3.x << " " << p3.y << " " << p3.z + << ", radius = " << p.w) + + const float referenceValue = 0.f; + + const float sampledValue = vklComputeSample(vklSampler, &p3); + INFO("sampled = " << sampledValue) + + REQUIRE(referenceValue == sampledValue); + } + + vklRelease(vklSampler); +} + +TEST_CASE("Particle volume radius", "[volume_sampling]") +{ + initializeOpenVKL(); + + const size_t numParticles = 100; + + // particles will be seeded within these bounds + box3f bounds = box3f(-1.f, 1.f); + + int32_t randomSeed = 0; + + // create random number distributions for point centers + std::mt19937 gen(randomSeed); + + std::uniform_real_distribution centerDistribution_x(bounds.lower.x, + bounds.upper.x); + std::uniform_real_distribution centerDistribution_y(bounds.lower.y, + bounds.upper.y); + std::uniform_real_distribution centerDistribution_z(bounds.lower.z, + bounds.upper.z); + + // populate the particles + std::vector particles( + numParticles); // position (x, y, z) and radius (w) + + // random particle positions, zero radius + for (int i = 0; i < numParticles; i++) { + auto &p = particles[i]; + p.x = centerDistribution_x(gen); + p.y = centerDistribution_y(gen); + p.z = centerDistribution_z(gen); + p.w = 0.f; + } + + VKLVolume volume = vklNewVolume(getOpenVKLDevice(), "particle"); + + VKLData positionsData = vklNewData(getOpenVKLDevice(), + numParticles, + VKL_VEC3F, + particles.data(), + VKL_DATA_SHARED_BUFFER, + sizeof(vec4f)); + vklSetData(volume, "particle.position", positionsData); + vklRelease(positionsData); + + VKLData radiiData = vklNewData(getOpenVKLDevice(), + numParticles, + VKL_FLOAT, + &(particles.data()[0].w), + VKL_DATA_SHARED_BUFFER, + sizeof(vec4f)); + vklSetData(volume, "particle.radius", radiiData); + vklRelease(radiiData); + + vklSetFloat(volume, "background", 0.f); + + vklCommit(volume); + + sampling_at_particle_centers(volume, particles); + + sampling_at_particle_centers_delta(volume, particles); + + vklRelease(volume); + + shutdownOpenVKL(); +} From 3eb0bfe415709d8714ea8f0af246a2b98dd4c18d Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Tue, 11 Jan 2022 15:26:37 -0700 Subject: [PATCH 15/25] VDB and structuredRegular now support indexToObject as a VKL_AFFINE3F parameter; takes precedence over (gridOrigin, gridSpacing) for structuredRegular. --- doc/api.md | 27 +++++++++++------ openvkl/common/ManagedObject.h | 22 +++++++++++++- .../devices/cpu/volume/vdb/DenseVdbVolume.cpp | 30 ++++++++----------- openvkl/devices/cpu/volume/vdb/VdbVolume.cpp | 19 ------------ openvkl/devices/cpu/volume/vdb/VdbVolume.h | 27 ++++++++++++++++- .../openvkl/utility/vdb/VdbVolumeBuffers.h | 23 ++++---------- 6 files changed, 82 insertions(+), 66 deletions(-) diff --git a/doc/api.md b/doc/api.md index e9d5651f..cd337ee8 100644 --- a/doc/api.md +++ b/doc/api.md @@ -482,6 +482,14 @@ table below. vec3f gridSpacing $(1, 1, 1)$ size of the grid cells in object space + affine3f indexToObject 1, 0, 0, Defines the transformation from index + 0, 1, 0, space to object space. In index space, + 0, 0, 1, the grid is an axis-aligned regular + 0, 0, 0 grid, and grid cells have size (1,1,1). + This parameter takes precedence over + `gridOrigin` and `gridSpacing`, if + provided. + uint32 temporalFormat `VKL_TEMPORAL_FORMAT_CONSTANT` The temporal format for this volume. Use `VKLTemporalFormat` for named constants. @@ -839,15 +847,16 @@ following parameters: ------------ ------------------------------------- ------------------------------ --------------------------------------- Type Name Default Description ------------ ------------------------------------- ------------------------------ --------------------------------------- - float[] indexToObject 1, 0, 0, An array of 12 values of type `float` - 0, 1, 0, that define the transformation from - 0, 0, 1, index space to object space. - 0, 0, 0 In index space, the grid is an - axis-aligned regular grid, and leaf - voxels have size (1,1,1). - The first 9 values are interpreted - as a row-major linear transformation - matrix. The last 3 values are the + affine3f indexToObject 1, 0, 0, Defines the transformation from index + float[] 0, 1, 0, space to object space. In index space, + 0, 0, 1, the grid is an axis-aligned regular + 0, 0, 0 grid, and leaf voxels have size (1,1,1). + A `vkl_affine3f` can be provided; + alternatively an array of 12 values of + type `float` can be used, where the + first 9 values are interpreted as a + row-major linear transformation matrix, + and the last 3 values are the translation of the grid origin. uint32[] node.format For each input node, the data format. diff --git a/openvkl/common/ManagedObject.h b/openvkl/common/ManagedObject.h index 8f294e97..3212a7eb 100644 --- a/openvkl/common/ManagedObject.h +++ b/openvkl/common/ManagedObject.h @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Intel Corporation +// Copyright 2019-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -29,6 +29,10 @@ namespace openvkl { virtual ~ManagedObject() override; + // returns if a parameter of the given type is present + template + bool hasParamT(const char *name); + // uses the provided default value if the parameter is not set template T getParam(const char *name, T valIfNotFound); @@ -108,6 +112,22 @@ namespace openvkl { // Inlined definitions ////////////////////////////////////////////////////// + template + inline bool ManagedObject::hasParamT(const char *name) + { + if (!hasParam(name)) { + return false; + } + + Param *param = findParam(name); + + if (param->data.is()) { + return true; + } + + return false; + } + template inline T ManagedObject::getParam(const char *name, T valIfNotFound) { diff --git a/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp b/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp index bb63f7f4..79c42297 100644 --- a/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp +++ b/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp @@ -1,4 +1,4 @@ -// Copyright 2021 Intel Corporation +// Copyright 2021-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "DenseVdbVolume.h" @@ -33,25 +33,19 @@ namespace openvkl { template void DenseVdbVolume::initIndexSpaceTransforms() { - std::vector i2w{gridSpacing.x, - 0, - 0, - 0, - gridSpacing.y, - 0, - 0, - 0, - gridSpacing.z, - gridOrigin.x, - gridOrigin.y, - gridOrigin.z}; - AffineSpace3f i2o(one); - i2o.l = LinearSpace3f(vec3f(i2w[0], i2w[1], i2w[2]), - vec3f(i2w[3], i2w[4], i2w[5]), - vec3f(i2w[6], i2w[7], i2w[8])); - i2o.p = vec3f(i2w[9], i2w[10], i2w[11]); + // support indexToObject transformation (instead of gridOrigin, + // gridSpacing) if provided + if (this->template hasParamT("indexToObject") || + this->template hasParamDataT("indexToObject")) { + i2o = getParamAffineSpace3f(this, "indexToObject"); + } else { + i2o.l = LinearSpace3f(vec3f(gridSpacing.x, 0.f, 0.f), + vec3f(0.f, gridSpacing.y, 0.f), + vec3f(0.f, 0.f, gridSpacing.z)); + i2o.p = vec3f(gridOrigin.x, gridOrigin.y, gridOrigin.z); + } writeTransform(i2o, this->grid->indexToObject); diff --git a/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp b/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp index cd325f39..e05e16fe 100644 --- a/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp +++ b/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp @@ -368,25 +368,6 @@ namespace openvkl { } } - /* - * Load an affine 4x3 matrix from the given object. - */ - inline AffineSpace3f getParamAffineSpace3f(ManagedObject *obj, - const char *name) - { - Ref> dataIndexToObject = - obj->template getParamDataT(name, nullptr); - AffineSpace3f a(one); - if (dataIndexToObject && dataIndexToObject->size() >= 12) { - const DataT &i2w = *dataIndexToObject; - a.l = LinearSpace3f(vec3f(i2w[0], i2w[1], i2w[2]), - vec3f(i2w[3], i2w[4], i2w[5]), - vec3f(i2w[6], i2w[7], i2w[8])); - a.p = vec3f(i2w[9], i2w[10], i2w[11]); - } - return a; - } - template void VdbVolume::initIndexSpaceTransforms() { diff --git a/openvkl/devices/cpu/volume/vdb/VdbVolume.h b/openvkl/devices/cpu/volume/vdb/VdbVolume.h index 4e1febdc..8ca4f27a 100644 --- a/openvkl/devices/cpu/volume/vdb/VdbVolume.h +++ b/openvkl/devices/cpu/volume/vdb/VdbVolume.h @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Intel Corporation +// Copyright 2019-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -30,6 +30,31 @@ namespace openvkl { // These may be used in VdbVolume and derived classes + /* + * Load an affine 4x3 matrix from the given object. + */ + inline AffineSpace3f getParamAffineSpace3f(ManagedObject *obj, + const char *name) + { + AffineSpace3f a(one); + + if (obj->hasParamT(name)) { + a = obj->getParam(name); + } else { + Ref> dataIndexToObject = + obj->template getParamDataT(name, nullptr); + + if (dataIndexToObject && dataIndexToObject->size() >= 12) { + const DataT &i2w = *dataIndexToObject; + a.l = LinearSpace3f(vec3f(i2w[0], i2w[1], i2w[2]), + vec3f(i2w[3], i2w[4], i2w[5]), + vec3f(i2w[6], i2w[7], i2w[8])); + a.p = vec3f(i2w[9], i2w[10], i2w[11]); + } + } + return a; + } + /* * Store the given transformation in a format that our ISPC implementation * can work with. diff --git a/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h b/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h index 95df55ad..cbfb4754 100644 --- a/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h +++ b/utility/vdb/include/openvkl/utility/vdb/VdbVolumeBuffers.h @@ -132,8 +132,7 @@ namespace openvkl { /* * The grid transform (index space to object space). */ - float indexToObject[12] = { - 1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f}; + AffineSpace3f indexToObject = AffineSpace3f(one); box3i activeVoxelsBoundingBox = empty; @@ -205,18 +204,9 @@ namespace openvkl { float p1, float p2) { - indexToObject[0] = l00; - indexToObject[1] = l01; - indexToObject[2] = l02; - indexToObject[3] = l10; - indexToObject[4] = l11; - indexToObject[5] = l12; - indexToObject[6] = l20; - indexToObject[7] = l21; - indexToObject[8] = l22; - indexToObject[9] = p0; - indexToObject[10] = p1; - indexToObject[11] = p2; + indexToObject.l = LinearSpace3f( + vec3f(l00, l01, l02), vec3f(l10, l11, l12), vec3f(l20, l21, l22)); + indexToObject.p = vec3f(p0, p1, p2); } inline void VdbVolumeBuffers::setActiveVoxelsBoundingBox(const box3i &bbox) @@ -465,10 +455,7 @@ namespace openvkl { { VKLVolume volume = vklNewVolume(device, "vdb"); - VKLData transformData = - vklNewData(device, 12, VKL_FLOAT, indexToObject, VKL_DATA_DEFAULT); - vklSetData(volume, "indexToObject", transformData); - vklRelease(transformData); + vklSetParam(volume, "indexToObject", VKL_AFFINE3F, &indexToObject); if (!activeVoxelsBoundingBox.empty()) { vklSetParam( From 4dc34afa5469a8ab4fc0cd2a06b6c1e31b704165 Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Thu, 27 Jan 2022 11:51:42 -0700 Subject: [PATCH 16/25] particle volumes: zero-radius particles are ignored; clarify behavior in API documentation. --- doc/api.md | 3 + .../cpu/volume/particle/ParticleVolume.cpp | 40 ++++++++++-- .../cpu/volume/particle/ParticleVolume.h | 24 +++---- .../cpu/volume/particle/ParticleVolume.ispc | 5 +- testing/apps/tests/particle_volume_radius.cpp | 62 ++++++++++--------- 5 files changed, 82 insertions(+), 52 deletions(-) diff --git a/doc/api.md b/doc/api.md index cd337ee8..53926203 100644 --- a/doc/api.md +++ b/doc/api.md @@ -1063,6 +1063,9 @@ radial basis function phi, for each particle that overlaps it. Gradients are similarly computed, based on the summed analytical contributions of each contributing particle. +Particles with a radius less than or equal to zero are ignored. At least one +valid particle (radius greater than zero) must be provided. + The Open VKL implementation is similar to direct evaluation of samples in Reda et al.[2]. It uses an Embree-built BVH with a custom traversal, similar to the method in [1]. diff --git a/openvkl/devices/cpu/volume/particle/ParticleVolume.cpp b/openvkl/devices/cpu/volume/particle/ParticleVolume.cpp index 258541ef..33cdbbf2 100644 --- a/openvkl/devices/cpu/volume/particle/ParticleVolume.cpp +++ b/openvkl/devices/cpu/volume/particle/ParticleVolume.cpp @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Intel Corporation +// Copyright 2020-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "ParticleVolume.h" @@ -48,6 +48,10 @@ namespace openvkl { // length const size_t numParticles = positions->size(); + if (numParticles == 0) { + throw std::runtime_error("no particles provided"); + } + if (radii->size() != numParticles) { throw std::runtime_error( "particle.radius array must have same number of elements as " @@ -160,6 +164,35 @@ namespace openvkl { primRadii[taskIndex] = radius; }); + // filter out any prims with radius <= 0. note we need to leave other + // arrays such as primRadii unchanged, as we will not change primID values + // in this operation. + const bool haveZeroRadiiParticles = std::any_of( + primRadii.begin(), primRadii.end(), [](float r) { return r <= 0; }); + + if (haveZeroRadiiParticles) { + containers::AlignedVector primsFiltered; + primsFiltered.reserve(numParticles); + + std::copy_if( + prims.begin(), + prims.end(), + std::back_inserter(primsFiltered), + [&](RTCBuildPrimitive p) { return primRadii[p.primID] > 0; }); + + LogMessageStream(this->device.ptr, VKL_LOG_DEBUG) + << "filtered out " << prims.size() - primsFiltered.size() << " / " + << prims.size() << " particles with <= 0 radius" << std::endl; + + if (primsFiltered.size() == 0) { + throw std::runtime_error("no particles with radius > 0 provided"); + } + + prims = primsFiltered; + } + + numBVHParticles = prims.size(); + rtcBVH = rtcNewBVH(rtcDevice); if (!rtcBVH) { throw std::runtime_error("bvh creation failure"); @@ -212,13 +245,12 @@ namespace openvkl { const float uncertainty = 0.05f; // build vector of leaf nodes - const size_t numParticles = positions->size(); std::vector leafNodes; - leafNodes.reserve(numParticles); + leafNodes.reserve(numBVHParticles); getLeafNodes(rtcRoot, leafNodes); - if (leafNodes.size() != numParticles) { + if (leafNodes.size() != numBVHParticles) { throw std::runtime_error("incorrect number of leaf nodes found"); } diff --git a/openvkl/devices/cpu/volume/particle/ParticleVolume.h b/openvkl/devices/cpu/volume/particle/ParticleVolume.h index 40be522d..3ac01beb 100644 --- a/openvkl/devices/cpu/volume/particle/ParticleVolume.h +++ b/openvkl/devices/cpu/volume/particle/ParticleVolume.h @@ -23,21 +23,11 @@ namespace openvkl { static_assert(sizeof(ParticleLeafNode) == sizeof(LeafNode), "ParticleLeafNode incompatible with LeafNode"); - if (radius < 0.f) { - throw std::runtime_error("particle radii must all be >= 0"); - } else if (radius == 0.f) { - // we require non-zero nominal lengths; note however this is only used - // in BVH construction / traversal; actual sampling will not consider - // this epsilon - const float epsilon = std::numeric_limits::min(); - nominalLength.x = -epsilon; - nominalLength.y = epsilon; - nominalLength.z = epsilon; - } else { - nominalLength.x = -radius; - nominalLength.y = radius; - nominalLength.z = radius; - } + assert(radius > 0.f); + + nominalLength.x = -radius; + nominalLength.y = radius; + nominalLength.z = radius; // note that valueRange will be set separately in computeValueRanges() } @@ -94,6 +84,10 @@ namespace openvkl { Ref> background; + // number of particles included in the BVH, which will not include any + // zero-radius particles + size_t numBVHParticles{0}; + RTCBVH rtcBVH{0}; RTCDevice rtcDevice{0}; Node *rtcRoot{nullptr}; diff --git a/openvkl/devices/cpu/volume/particle/ParticleVolume.ispc b/openvkl/devices/cpu/volume/particle/ParticleVolume.ispc index 11d7487b..46631497 100644 --- a/openvkl/devices/cpu/volume/particle/ParticleVolume.ispc +++ b/openvkl/devices/cpu/volume/particle/ParticleVolume.ispc @@ -22,10 +22,7 @@ inline void getParticleContributionGaussian(const VKLParticleVolume *uniform delta = objectCoordinates - position; - if (radius == 0.f) { - value = length(delta) == 0.f ? w : 0.f; - return; - } else if (length(delta) > radius * self->radiusSupportFactor) { + if (length(delta) > radius * self->radiusSupportFactor) { value = 0.f; return; } diff --git a/testing/apps/tests/particle_volume_radius.cpp b/testing/apps/tests/particle_volume_radius.cpp index 8f646402..07979167 100644 --- a/testing/apps/tests/particle_volume_radius.cpp +++ b/testing/apps/tests/particle_volume_radius.cpp @@ -8,6 +8,10 @@ using namespace rkcommon; using namespace openvkl::testing; +// we need at least one particle with radius > 0; we'll place it at the origin, +// with this radius. +static float originParticleRadius = 1e-3f; + // verifies sampling at particle center yields the particle weight static void sampling_at_particle_centers(VKLVolume vklVolume, const std::vector particles) @@ -23,35 +27,17 @@ static void sampling_at_particle_centers(VKLVolume vklVolume, INFO("particle i = " << i << ", p = " << p.x << " " << p.y << " " << p.z << ", radius = " << p.w) - const float referenceValue = 1.f; - - const float sampledValue = vklComputeSample(vklSampler, &p3); - INFO("sampled = " << sampledValue) - - REQUIRE(referenceValue == sampledValue); - } - - vklRelease(vklSampler); -} - -// verifies that sampling outside of the particle center yields zero -static void sampling_at_particle_centers_delta( - VKLVolume vklVolume, const std::vector particles) -{ - VKLSampler vklSampler = vklNewSampler(vklVolume); - vklCommit(vklSampler); - - const float epsilon = 1e-6f; - - for (size_t i = 0; i < particles.size(); i++) { - const vec4f &p = particles[i]; - - const vkl_vec3f p3{p.x + epsilon, p.y + epsilon, p.z + epsilon}; + const bool zeroRadiusParticle = p.w <= 0.f; - INFO("particle i = " << i << ", p = " << p3.x << " " << p3.y << " " << p3.z - << ", radius = " << p.w) + // skip testing any zero-radius particles near the origin (non-zero radius) + // particle; this will be random and rare + if (zeroRadiusParticle && + length(vec3f(p) - vec3f(0.f)) <= originParticleRadius) { + continue; + } - const float referenceValue = 0.f; + // if the particle radius is zero, then the sampled results should be zero + const float referenceValue = zeroRadiusParticle ? 0.f : 1.f; const float sampledValue = vklComputeSample(vklSampler, &p3); INFO("sampled = " << sampledValue) @@ -88,7 +74,7 @@ TEST_CASE("Particle volume radius", "[volume_sampling]") numParticles); // position (x, y, z) and radius (w) // random particle positions, zero radius - for (int i = 0; i < numParticles; i++) { + for (int i = 0; i < numParticles - 1; i++) { auto &p = particles[i]; p.x = centerDistribution_x(gen); p.y = centerDistribution_y(gen); @@ -96,6 +82,12 @@ TEST_CASE("Particle volume radius", "[volume_sampling]") p.w = 0.f; } + // need at least one particle with > 0 radius for a valid volume + particles.back().x = 0.f; + particles.back().y = 0.f; + particles.back().z = 0.f; + particles.back().w = originParticleRadius; + VKLVolume volume = vklNewVolume(getOpenVKLDevice(), "particle"); VKLData positionsData = vklNewData(getOpenVKLDevice(), @@ -116,13 +108,25 @@ TEST_CASE("Particle volume radius", "[volume_sampling]") vklSetData(volume, "particle.radius", radiiData); vklRelease(radiiData); + const float radiusSupportFactor = 3.f; // default + vklSetFloat(volume, "radiusSupportFactor", radiusSupportFactor); + vklSetFloat(volume, "background", 0.f); vklCommit(volume); sampling_at_particle_centers(volume, particles); - sampling_at_particle_centers_delta(volume, particles); + // bounding box should not include zero radius particles + vkl_box3f boundingBox = vklGetBoundingBox(volume); + + REQUIRE((boundingBox.lower.x == -originParticleRadius * radiusSupportFactor && + boundingBox.lower.y == -originParticleRadius * radiusSupportFactor && + boundingBox.lower.z == -originParticleRadius * radiusSupportFactor)); + + REQUIRE((boundingBox.upper.x == originParticleRadius * radiusSupportFactor && + boundingBox.upper.y == originParticleRadius * radiusSupportFactor && + boundingBox.upper.z == originParticleRadius * radiusSupportFactor)); vklRelease(volume); From 0eabb57a05d8651aa6933312af829eb217f91854 Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Mon, 31 Jan 2022 13:27:15 -0700 Subject: [PATCH 17/25] superbuild: update ISPC v1.17.0 Linux binary hash. --- superbuild/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superbuild/CMakeLists.txt b/superbuild/CMakeLists.txt index f1624d12..8ce99d57 100644 --- a/superbuild/CMakeLists.txt +++ b/superbuild/CMakeLists.txt @@ -105,7 +105,7 @@ if (BUILD_ISPC) set(_ISPC_HASH "e9a7cc98f69357482985bcbf69fa006632cee7b3606069b4d5e16dc62092d660") else() set(_ISPC_URL "${ISPC_BASE_URL}/ispc-v${ISPC_VERSION}-linux.tar.gz") - set(_ISPC_HASH "1ddd189e6b679ab269f8580fef4dd0143862c4e503d35c52d63c71721877f2ce") + set(_ISPC_HASH "6acc5df75efdce437f79b1b6489be8567c6d009e19dcc4851b9b37012afce1f7") endif() set(ISPC_URL "${_ISPC_URL}" CACHE STRING "URL of the ISPC archive.") set(ISPC_HASH "${_ISPC_HASH}" CACHE STRING "SHA256 hash of the ISPC archive.") From 51c157c58ea67255200b0f3c354eddfa198d71ed Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Thu, 27 Jan 2022 14:54:05 -0700 Subject: [PATCH 18/25] vklExamples: add intervalResolutionHint parameter for IntervalIteratorDebug and RayMarchIterator renderers. --- examples/interactive/ParameterGui.cpp | 6 +++++- examples/interactive/renderer/IntervalIteratorDebug.cpp | 6 +++++- examples/interactive/renderer/IntervalIteratorDebug.h | 3 ++- examples/interactive/renderer/RayMarchIteratorRenderer.cpp | 6 +++++- examples/interactive/renderer/RayMarchIteratorRenderer.h | 3 ++- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/examples/interactive/ParameterGui.cpp b/examples/interactive/ParameterGui.cpp index 0c17f5e3..c4f6e818 100644 --- a/examples/interactive/ParameterGui.cpp +++ b/examples/interactive/ParameterGui.cpp @@ -1,4 +1,4 @@ -// Copyright 2021 Intel Corporation +// Copyright 2021-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "ParameterGui.h" @@ -265,6 +265,8 @@ namespace openvkl { ImGui::PushID(id.c_str()); + changed |= ImGui::SliderFloat( + "intervalResolutionHint", &p.intervalResolutionHint, 0.f, 1.f); changed |= ImGui::SliderFloat("Sampling rate", &p.samplingRate, 0.01f, 4.f); @@ -310,6 +312,8 @@ namespace openvkl { ImGui::PushID(id.c_str()); + changed |= ImGui::SliderFloat( + "intervalResolutionHint", &p.intervalResolutionHint, 0.f, 1.f); changed |= ImGui::SliderFloat("Color scale", &p.intervalColorScale, 1.f, 32.f); changed |= diff --git a/examples/interactive/renderer/IntervalIteratorDebug.cpp b/examples/interactive/renderer/IntervalIteratorDebug.cpp index c4720415..df4fdd87 100644 --- a/examples/interactive/renderer/IntervalIteratorDebug.cpp +++ b/examples/interactive/renderer/IntervalIteratorDebug.cpp @@ -1,4 +1,4 @@ -// Copyright 2021 Intel Corporation +// Copyright 2021-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "IntervalIteratorDebug.h" @@ -28,6 +28,10 @@ namespace openvkl { vklSetInt( intervalContext, "attributeIndex", rendererParams->attributeIndex); + vklSetFloat(intervalContext, + "intervalResolutionHint", + params->intervalResolutionHint); + // set interval context value ranges based on transfer function positive // opacity intervals, if we have any VKLData valueRangesData = nullptr; diff --git a/examples/interactive/renderer/IntervalIteratorDebug.h b/examples/interactive/renderer/IntervalIteratorDebug.h index 5dfad725..e27cb69e 100644 --- a/examples/interactive/renderer/IntervalIteratorDebug.h +++ b/examples/interactive/renderer/IntervalIteratorDebug.h @@ -1,4 +1,4 @@ -// Copyright 2021 Intel Corporation +// Copyright 2021-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -10,6 +10,7 @@ namespace openvkl { struct IntervalIteratorDebugParams { + float intervalResolutionHint{0.5f}; float intervalColorScale{4.f}; float intervalOpacity{0.25f}; bool firstIntervalOnly{false}; diff --git a/examples/interactive/renderer/RayMarchIteratorRenderer.cpp b/examples/interactive/renderer/RayMarchIteratorRenderer.cpp index e6b8e796..614e8c96 100644 --- a/examples/interactive/renderer/RayMarchIteratorRenderer.cpp +++ b/examples/interactive/renderer/RayMarchIteratorRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright 2021 Intel Corporation +// Copyright 2021-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "RayMarchIteratorRenderer.h" @@ -30,6 +30,10 @@ namespace openvkl { vklSetInt( intervalContext, "attributeIndex", rendererParams->attributeIndex); + vklSetFloat(intervalContext, + "intervalResolutionHint", + params->intervalResolutionHint); + // set interval context value ranges based on transfer function positive // opacity intervals, if we have any VKLData valueRangesData = nullptr; diff --git a/examples/interactive/renderer/RayMarchIteratorRenderer.h b/examples/interactive/renderer/RayMarchIteratorRenderer.h index a204fbe9..1097230f 100644 --- a/examples/interactive/renderer/RayMarchIteratorRenderer.h +++ b/examples/interactive/renderer/RayMarchIteratorRenderer.h @@ -1,4 +1,4 @@ -// Copyright 2021 Intel Corporation +// Copyright 2021-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -10,6 +10,7 @@ namespace openvkl { struct RayMarchIteratorRendererParams { + float intervalResolutionHint{0.5f}; float samplingRate{1.f}; }; From 8210c174f41e0856bf340c3b3c2c1677b223ba36 Mon Sep 17 00:00:00 2001 From: Johannes Meng Date: Thu, 20 Jan 2022 14:31:33 -0700 Subject: [PATCH 19/25] add set of minimal examples for use in webinar. --- examples/CMakeLists.txt | 6 +- examples/minimal/CMakeLists.txt | 9 ++ examples/minimal/README.md | 18 ++++ examples/minimal/create_voxels.h | 27 ++++++ examples/minimal/field.h | 17 ++++ examples/minimal/framebuffer.h | 162 +++++++++++++++++++++++++++++++ examples/minimal/minimal_01.cpp | 16 +++ examples/minimal/minimal_02.cpp | 36 +++++++ examples/minimal/minimal_03.cpp | 75 ++++++++++++++ examples/minimal/minimal_04.cpp | 55 +++++++++++ examples/minimal/minimal_05.cpp | 66 +++++++++++++ examples/minimal/minimal_06.cpp | 87 +++++++++++++++++ 12 files changed, 573 insertions(+), 1 deletion(-) create mode 100755 examples/minimal/CMakeLists.txt create mode 100644 examples/minimal/README.md create mode 100755 examples/minimal/create_voxels.h create mode 100755 examples/minimal/field.h create mode 100755 examples/minimal/framebuffer.h create mode 100755 examples/minimal/minimal_01.cpp create mode 100755 examples/minimal/minimal_02.cpp create mode 100755 examples/minimal/minimal_03.cpp create mode 100755 examples/minimal/minimal_04.cpp create mode 100755 examples/minimal/minimal_05.cpp create mode 100755 examples/minimal/minimal_06.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index bf8e4a9f..f387f8b4 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,4 +1,4 @@ -## Copyright 2019-2020 Intel Corporation +## Copyright 2019-2022 Intel Corporation ## SPDX-License-Identifier: Apache-2.0 ## "Hello world" VKL tutorials ## @@ -14,3 +14,7 @@ add_subdirectory(ispc) ## Interacive Examples ## add_subdirectory(interactive) + +## Minimal Console-based Examples ## + +add_subdirectory(minimal) diff --git a/examples/minimal/CMakeLists.txt b/examples/minimal/CMakeLists.txt new file mode 100755 index 00000000..3d60157d --- /dev/null +++ b/examples/minimal/CMakeLists.txt @@ -0,0 +1,9 @@ +## Copyright 2022 Intel Corporation +## SPDX-License-Identifier: Apache-2.0 + +# The minimal_01 ... minimal_06 examples gradually increase in complexity +foreach(i 01 02 03 04 05 06) + add_executable(vklMinimal_${i} minimal_${i}.cpp ${VKL_RESOURCE}) + target_link_libraries(vklMinimal_${i} PRIVATE openvkl) + install(TARGETS vklMinimal_${i} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +endforeach() diff --git a/examples/minimal/README.md b/examples/minimal/README.md new file mode 100644 index 00000000..75472ee7 --- /dev/null +++ b/examples/minimal/README.md @@ -0,0 +1,18 @@ +# Intel® Open Volume Kernel Library: Minimal Examples + +This directory contains a sequence of minimal code examples that make use of +Open VKL. These examples are designed to be read and understood in sequence; +each example builds upon the previous one. + +The examples provided are: + +- `minimal_01.cpp`: prerequisite code infrastructure for managing a framebuffer, + using a transfer function, and drawing the frame buffer to the terminal. +- `minimal_02.cpp`: initializing Open VKL +- `minimal_03.cpp`: instantiating a VKL volume, sampler, and rendering a slice +- `minimal_04.cpp`: changing volume types +- `minimal_05.cpp`: creating a ray marching volume renderer +- `minimal_06.cpp`: creating an isosurface renderer + +For more complex examples, see the `vklExamples` application and corresponding +code. diff --git a/examples/minimal/create_voxels.h b/examples/minimal/create_voxels.h new file mode 100755 index 00000000..a6fc3ea2 --- /dev/null +++ b/examples/minimal/create_voxels.h @@ -0,0 +1,27 @@ +// Copyright 2021-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "field.h" + +#include +#include + +// The structured regular volume expects a data buffer that contains +// all voxel values. We create it here by sampling the field() function, but +// this data could be the output of a simulation, or loaded from disk. +inline std::vector createVoxels(size_t res) +{ + std::vector voxels(res * res * res); + for (size_t z = 0; z < res; ++z) + for (size_t y = 0; y < res; ++y) + for (size_t x = 0; x < res; ++x) { + const float fx = x / static_cast(res); + const float fy = y / static_cast(res); + const float fz = z / static_cast(res); + const size_t idx = z * res * res + y * res + x; + voxels[idx] = field(fx, fy, fz); + } + return voxels; +} diff --git a/examples/minimal/field.h b/examples/minimal/field.h new file mode 100755 index 00000000..2e675bba --- /dev/null +++ b/examples/minimal/field.h @@ -0,0 +1,17 @@ +// Copyright 2021-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#if defined(_MSC_VER) && !defined(NOMINMAX) +#define NOMINMAX +#endif + +#include +inline float field(float x, float y, float z) +{ + constexpr float freq = 11.f; + return (std::sin(freq * x * x * x) + std::sin(freq * y * y) + + std::cos(freq * z)) / + 3.f; +} diff --git a/examples/minimal/framebuffer.h b/examples/minimal/framebuffer.h new file mode 100755 index 00000000..3444bde8 --- /dev/null +++ b/examples/minimal/framebuffer.h @@ -0,0 +1,162 @@ +// Copyright 2021-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#if defined(_MSC_VER) && !defined(NOMINMAX) +#define NOMINMAX +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +/* On Windows, we need to explicitly enable VT processing so that + * the ANSI color codes we use will be supported. */ +#if defined(_MSC_VER) + + #include + + void enableAnsiColor() + { + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + if (hStdout) { + DWORD outputMode = 0; + if (GetConsoleMode(hStdout, &outputMode)) + { + outputMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(hStdout, outputMode); + } + } + } +#else + void enableAnsiColor() {} +#endif + +using Color = rkcommon::math::vec4f; + +/* + * We use this transfer function to map scalar values to + * colors with opacity. + */ +inline Color transferFunction(float v) +{ + Color p = {0.f}; + if (std::isfinite(v)) + { + const float a = std::max(0.f, std::min(std::abs(v), 1.f)); + p = (v<0) + ? Color{ 233.f/255.f, 97.f/255.f, 21.f/255.f, a } + : Color{ 0.f, 163.f/255.f, 246.f/255.f, a }; + } + return p; +} + +/* + * Porter-Duff over blending. Note that we are not using + * premultiplied colors here for simplicity. + */ +inline Color over(const Color &c1, const Color &c2) +{ + Color c; + c.w = c1.w + (1.f-c1.w) * c2.w; + c.x = (c1.w * (1.f-c2.w) * c1.x + c2.w * c2.x) / c.w; + c.y = (c1.w * (1.f-c2.w) * c1.y + c2.w * c2.y) / c.w; + c.z = (c1.w * (1.f-c2.w) * c1.z + c2.w * c2.z) / c.w; + return c; +} + +/* + * A basic framebuffer class that can draw itself to the terminal using + * ANSI control sequences. + */ +class Framebuffer +{ + public: + using Pixel = Color; + + public: + Framebuffer() = default; + Framebuffer(size_t w, size_t h); + + template + void generate(Functor &&f); + + void drawToTerminal() const; + + private: + size_t idx(size_t x, size_t y) const; + std::string toAnsi(const Pixel &p) const; + + private: + size_t w{0}; + size_t h{0}; + std::vector buffer; +}; + +inline Framebuffer::Framebuffer(size_t w, size_t h) + : w(w), h(h), buffer(w * h, Pixel{0.f}) +{ + assert(w > 0); + assert(h > 0); + enableAnsiColor(); +} + +template +inline void Framebuffer::generate(Functor &&f) +{ + for (size_t y = 0; y < h; ++y) { + const float fy = y / static_cast(h); + for (size_t x = 0; x < w; ++x) { + const float fx = x / static_cast(w); + buffer[idx(x, y)] = f(fx, fy); + } + } +} + +inline void Framebuffer::drawToTerminal() const +{ + for (size_t y = 0; y < h; ++y) { + for (size_t x = 0; x < w; ++x) { + // Draw from top to bottom. + const size_t idx = (h-1-y) * w + x; + std::cout << toAnsi(buffer[idx]).c_str(); + } + std::cout << std::endl; + } +} + +inline size_t Framebuffer::idx(size_t x, size_t y) const +{ + return y * w + x; +} + +inline uint8_t premultAlpha(uint8_t v, uint8_t a) +{ + return static_cast(v * static_cast(a) / 255.f) & 0xFF; +} + +const int mapTo8bit(float v, float a) +{ + v *= a; + v *= 255.f; + v = std::max(0.f, std::min(v, 255.f)); + return static_cast(v) & 255; +} + +inline std::string Framebuffer::toAnsi(const Pixel &p) const +{ + std::ostringstream os; + os << "\x1b[48;2" + << ";" << mapTo8bit(p.x, p.w) + << ";" << mapTo8bit(p.y, p.w) + << ";" << mapTo8bit(p.z, p.w) + << "m \x1b[m"; + return os.str(); +} diff --git a/examples/minimal/minimal_01.cpp b/examples/minimal/minimal_01.cpp new file mode 100755 index 00000000..43db2bda --- /dev/null +++ b/examples/minimal/minimal_01.cpp @@ -0,0 +1,16 @@ +// Copyright 2021-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "framebuffer.h" + +int main(int argc, char **argv) +{ + Framebuffer fb(64, 32); + + fb.generate([&](float fx, float fy) { + return transferFunction(2*fx-1); + }); + fb.drawToTerminal(); + + return 0; +} diff --git a/examples/minimal/minimal_02.cpp b/examples/minimal/minimal_02.cpp new file mode 100755 index 00000000..5247597d --- /dev/null +++ b/examples/minimal/minimal_02.cpp @@ -0,0 +1,36 @@ +// Copyright 2021-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "framebuffer.h" + +// We must include the openvkl header. +#include + +int main(int argc, char **argv) +{ + // To initialize Open VKL, load the device module, which is essentially the + // backend implementation. Our current release supports only "cpu_device", + // which is highly optimized for vector CPU architectures. + vklLoadModule("cpu_device"); + + // The device itself will be manage all resources. "cpu" is the default and + // selects the native vector width for best performance. + VKLDevice device = vklNewDevice("cpu"); + + // Devices must be committed before use. This is because they support + // parameters, such as logging verbosity. + vklCommitDevice(device); + + Framebuffer fb(64, 32); + + fb.generate([&](float fx, float fy) { + return transferFunction(2*fx-1); + }); + fb.drawToTerminal(); + + // When the application is done with the device, release it! + // This will clean up the internal state. + vklReleaseDevice(device); + + return 0; +} diff --git a/examples/minimal/minimal_03.cpp b/examples/minimal/minimal_03.cpp new file mode 100755 index 00000000..4c10df09 --- /dev/null +++ b/examples/minimal/minimal_03.cpp @@ -0,0 +1,75 @@ +// Copyright 2021-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "create_voxels.h" +#include "framebuffer.h" + +// We must include the openvkl header. +#include + +int main(int argc, char **argv) +{ + vklLoadModule("cpu_device"); + VKLDevice device = vklNewDevice("cpu"); + vklCommitDevice(device); + + // "Load data from disk". (We generate the array procedurally). + constexpr size_t res = 128; + std::vector voxels = createVoxels(res); + + // Note that Open VKL uses a C99 API for maximum compatibility. + // So we will have to wrap the array we just created so that + // we can pass it to Open VKL. + + // Create a new volume. Volume objects are created on a device. + // We create a structured regular grid here, which is essentially + // a dense 3D array. + VKLVolume volume = vklNewVolume(device, "structuredRegular"); + + // We have to set a few parameters on the volume. + // First, Open VKL needs to know the extent of the volume: + vklSetVec3i(volume, "dimensions", res, res, res); + + // By default, the volume assumes a voxel size of 1. Scale it so the + // domain is [0, 1]. + const float spacing = 1.f / static_cast(res); + vklSetVec3f(volume, "gridSpacing", spacing, spacing, spacing); + + // Open VKL has a concept of typed Data objects. That's how we pass data + // buffers to a device. We create a shared buffer here to avoid copying + // the voxels. + VKLData voxelData = vklNewData( + device, voxels.size(), VKL_FLOAT, voxels.data(), VKL_DATA_SHARED_BUFFER); + + // Set the data parameter. We can release the data directly afterwards + // as Open VKL has a reference counting mechanism and will keep track + // internally. + // Note this is a shared buffer, so we have to keep voxels around. + vklSetData(volume, "data", voxelData); + vklRelease(voxelData); + + // Finally, commit. This may build acceleration structures, etc. + vklCommit(volume); + + // Instead of drawing the field directly into our framebuffer, we will instead + // sample the volume we just created. To do that, we need a sampler object. + VKLSampler sampler = vklNewSampler(volume); + vklCommit(sampler); + + Framebuffer fb(64, 32); + + fb.generate([&](float fx, float fy) { + // To sample, we call vklComputeSample on our sampler object. + const vkl_vec3f p = {fx, fy, 0.f}; + return transferFunction(vklComputeSample(sampler, &p)); + }); + + fb.drawToTerminal(); + + // Release the volume to clean up! + vklRelease(sampler); + vklRelease(volume); + vklReleaseDevice(device); + + return 0; +} diff --git a/examples/minimal/minimal_04.cpp b/examples/minimal/minimal_04.cpp new file mode 100755 index 00000000..9a95826c --- /dev/null +++ b/examples/minimal/minimal_04.cpp @@ -0,0 +1,55 @@ +// Copyright 2021-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "create_voxels.h" +#include "framebuffer.h" + +#include + +int main(int argc, char **argv) +{ + vklLoadModule("cpu_device"); + VKLDevice device = vklNewDevice("cpu"); + vklCommitDevice(device); + + constexpr size_t res = 128; + std::vector voxels = createVoxels(res); + + // One advantage of Open VKL is that we can use a different data structure + // with the same sampling API. + // Here, we replace our data structure with a structured spherical volume + // for a spherical domain. + VKLVolume volume = vklNewVolume(device, "structuredSpherical"); + + vklSetVec3i(volume, "dimensions", res, res, res); + const float spacing = 1.f / static_cast(res); + // We must adapt gridSpacing, as structuredSpherical expects spacing + // in spherical coordinates. + vklSetVec3f(volume, "gridSpacing", spacing, 180.f*spacing, 360.f*spacing); + + VKLData voxelData = vklNewData( + device, voxels.size(), VKL_FLOAT, voxels.data(), VKL_DATA_SHARED_BUFFER); + vklSetData(volume, "data", voxelData); + vklRelease(voxelData); + + vklCommit(volume); + + VKLSampler sampler = vklNewSampler(volume); + vklCommit(sampler); + + Framebuffer fb(64, 32); + + fb.generate([&](float fx, float fy) { + // Also try slice 1.0 to demonstrate a different view. + const vkl_vec3f p = {fx, fy, 0.f}; + return transferFunction(vklComputeSample(sampler, &p)); + }); + + fb.drawToTerminal(); + + vklRelease(sampler); + vklRelease(volume); + vklReleaseDevice(device); + + return 0; +} diff --git a/examples/minimal/minimal_05.cpp b/examples/minimal/minimal_05.cpp new file mode 100755 index 00000000..4de85cbe --- /dev/null +++ b/examples/minimal/minimal_05.cpp @@ -0,0 +1,66 @@ +// Copyright 2021-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "create_voxels.h" +#include "framebuffer.h" + +#include + +int main(int argc, char **argv) +{ + vklLoadModule("cpu_device"); + VKLDevice device = vklNewDevice("cpu"); + vklCommitDevice(device); + + constexpr size_t res = 128; + std::vector voxels = createVoxels(res); + + VKLVolume volume = vklNewVolume(device, "structuredRegular"); + vklSetVec3i(volume, "dimensions", res, res, res); + + const float spacing = 1.f / static_cast(res); + vklSetVec3f(volume, "gridSpacing", spacing, spacing, spacing); + VKLData voxelData = vklNewData( + device, voxels.size(), VKL_FLOAT, voxels.data(), VKL_DATA_SHARED_BUFFER); + vklSetData(volume, "data", voxelData); + vklRelease(voxelData); + + vklCommit(volume); + + VKLSampler sampler = vklNewSampler(volume); + vklCommit(sampler); + + Framebuffer fb(64, 32); + + // We trace the volume with simple ray marching. + // Conceptually, this is a series of camera-aligned, + // semi transparent planes. + // We walk along the ray in regular steps. + const int numSteps = 8; + const float tMax = 1.f; + const float tStep = tMax / numSteps; + fb.generate([&](float fx, float fy) { + Color color = {0.f}; + for (int i = 0; i < numSteps; ++i) + { + const vkl_vec3f p = {fx, fy, i * tStep}; + const Color c = transferFunction(vklComputeSample(sampler, &p)); + + // We use the over operator to blend semi-transparent + // "surfaces" together. + color = over(color, c); + + // Now we've created a very simple volume renderer using + // Open VKL! + } + return color; + }); + + fb.drawToTerminal(); + + vklRelease(sampler); + vklRelease(volume); + vklReleaseDevice(device); + + return 0; +} diff --git a/examples/minimal/minimal_06.cpp b/examples/minimal/minimal_06.cpp new file mode 100755 index 00000000..eb7ce617 --- /dev/null +++ b/examples/minimal/minimal_06.cpp @@ -0,0 +1,87 @@ +// Copyright 2021-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "create_voxels.h" +#include "framebuffer.h" + +#include + +#if defined(_MSC_VER) +#include +#else +#include +#endif + +int main(int argc, char **argv) +{ + vklLoadModule("cpu_device"); + VKLDevice device = vklNewDevice("cpu"); + vklCommitDevice(device); + + constexpr size_t res = 128; + std::vector voxels = createVoxels(res); + + VKLVolume volume = vklNewVolume(device, "structuredRegular"); + vklSetVec3i(volume, "dimensions", res, res, res); + const float spacing = 1.f / static_cast(res); + vklSetVec3f(volume, "gridSpacing", spacing, spacing, spacing); + VKLData voxelData = vklNewData( + device, voxels.size(), VKL_FLOAT, voxels.data(), VKL_DATA_SHARED_BUFFER); + vklSetData(volume, "data", voxelData); + vklRelease(voxelData); + vklCommit(volume); + + VKLSampler sampler = vklNewSampler(volume); + vklCommit(sampler); + + const float isovalues[] = { -.6f, -.1f, .4f, .9f }; + VKLHitIteratorContext context = vklNewHitIteratorContext(sampler); + VKLData isovaluesData = vklNewData(device, 4, VKL_FLOAT, isovalues); + vklSetData(context, "values", isovaluesData); + vklRelease(isovaluesData); + vklCommit(context); + + Framebuffer fb(64, 32); + + // We will create iterators below, and we will need to know how much memory + // to allocate. + const size_t iteratorSize = vklGetHitIteratorSize(context); + + fb.generate([&](float fx, float fy) { + // Set up the ray, as iterators work on rays. + const vkl_vec3f rayOrigin = {fx, fy, 0.f}; + const vkl_vec3f rayDirection = {0.f, 0.f, 1.f}; + const vkl_range1f rayTRange = {0.f, 1.f}; + + // Create a buffer for the iterator. +#if defined(_MSC_VER) + char *buffer = static_cast(_malloca(iteratorSize)); +#else + char *buffer = static_cast(alloca(iteratorSize)); +#endif + // Initialize iterator into the buffer we just created. + VKLHitIterator hitIterator = vklInitHitIterator( + context, &rayOrigin, &rayDirection, &rayTRange, 0.f, buffer); + + // Loop over all ray-isosurface intersections along our ray. + // vklIterateHit will return false when there + // is no more hit left. + VKLHit hit; + Color color = {0.f}; + while (vklIterateHit(hitIterator, &hit)) + { + const Color c = transferFunction(hit.sample); + color = over(color, c); + } + return color; + }); + + fb.drawToTerminal(); + + vklRelease(context); + vklRelease(sampler); + vklRelease(volume); + vklReleaseDevice(device); + + return 0; +} From 713805be4c48130d7b7491d98b15ea44bf64ab4e Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Thu, 10 Feb 2022 10:49:11 -0700 Subject: [PATCH 20/25] move to latest versions of dependencies. --- superbuild/CMakeLists.txt | 26 ++++----- testing/external/catch.hpp | 113 ++++++++++++++++++++----------------- 2 files changed, 73 insertions(+), 66 deletions(-) diff --git a/superbuild/CMakeLists.txt b/superbuild/CMakeLists.txt index 8ce99d57..e020e660 100644 --- a/superbuild/CMakeLists.txt +++ b/superbuild/CMakeLists.txt @@ -68,7 +68,7 @@ option(INSTALL_IN_SEPARATE_DIRECTORIES ) option(BUILD_DEPENDENCIES_ONLY - "Do not build Open VKL itself, only its dependencies" + "Do not build Open VKL itself, only its dependencies" OFF ) @@ -85,8 +85,8 @@ option(BUILD_OPENVKL_BENCHMARKS ## ======================================================================== ## ## Build dependencies. ## -## Use the BUILD_* options to enable or disable building in superbuild. If -## These options are OFF, then required dependencies must be available in the +## Use the BUILD_* options to enable or disable building in superbuild. If +## These options are OFF, then required dependencies must be available in the ## environment. ## ## For most of the dependencies, you may override the *_URL and *_HASH @@ -116,7 +116,7 @@ endif() option(BUILD_TBB "Build Intel Threading Building Blocks or search in environment?" ON) option(BUILD_TBB_FROM_SOURCE "Build Intel Threading Building Blocks from source or use pre-built version?" OFF) if (BUILD_TBB) - set(TBB_VERSION "2021.4.0" CACHE STRING "TBB version to download") + set(TBB_VERSION "2021.5.0" CACHE STRING "TBB version to download") if (BUILD_TBB_FROM_SOURCE) if (TBB_VERSION VERSION_LESS 2021) message(FATAL_ERROR "Only TBB 2021 and later are supported when building TBB from source") @@ -124,7 +124,7 @@ if (BUILD_TBB) string(REGEX REPLACE "(^[0-9]+\.[0-9]+\.[0-9]+$)" "v\\1" TBB_ARCHIVE ${TBB_VERSION}) set(_TBB_URL "https://github.com/oneapi-src/oneTBB/archive/refs/tags/${TBB_ARCHIVE}.zip") - set(_TBB_HASH "08ade531be2e4e904eb6bec8e01da51eb3b0e4e86738128eb2722b95e3fcb5e6") + set(_TBB_HASH "83ea786c964a384dd72534f9854b419716f412f9d43c0be88d41874763e7bb47") else() if (TBB_VERSION VERSION_LESS 2021) set(TBB_BASE_URL "https://github.com/oneapi-src/oneTBB/releases/download/v${TBB_VERSION}/tbb-${TBB_VERSION}") @@ -133,15 +133,15 @@ if (BUILD_TBB) endif() if (APPLE) set(_TBB_URL "${TBB_BASE_URL}-mac.tgz") - set(_TBB_HASH "519d599939c41808d6b9170253b4c993b40d481f2c56b1a3cf390aea37ddb355") + set(_TBB_HASH "388c1c25314e3251e38c87ade2323af74cdaae2aec9b68e4c206d61c30ef9c33") set(TBB_LIB_SUBDIR "") elseif(WIN32) set(_TBB_URL "${TBB_BASE_URL}-win.zip") - set(_TBB_HASH "3868c557739a7a5b74c985571648c066167fd7a0a8c63bdac00a6cfeeb58037f") + set(_TBB_HASH "096c004c7079af89fe990bb259d58983b0ee272afa3a7ef0733875bfe09fcd8e") set(TBB_LIB_SUBDIR "intel64/vc14") else() set(_TBB_URL "${TBB_BASE_URL}-lin.tgz") - set(_TBB_HASH "f1d26b9f3741e5d573050eef2902fcd739d2913c990f4c879a310e543fc5ffd5") + set(_TBB_HASH "74861b1586d6936b620cdab6775175de46ad8b0b36fa6438135ecfb8fb5bdf98") set(TBB_LIB_SUBDIR "intel64/gcc4.8") endif() endif() @@ -226,25 +226,25 @@ if (BUILD_OPENVDB) message(WARNING "Disabling OpenVDB support because the icc compiler version is too low (19.1 is required)") set(BUILD_OPENVDB OFF) else() - set(ILMBASE_VERSION "2.4.1") + set(ILMBASE_VERSION "2.5.7") set(ILMBASE_URL "https://github.com/AcademySoftwareFoundation/openexr/archive/v${ILMBASE_VERSION}.zip" CACHE STRING "URL of the IlmBase archive.") - set(ILMBASE_HASH "fd828641897f4ceb9277b61e3add25c3306adcb4670355ac7081d78cf7ee8f5f" + set(ILMBASE_HASH "95e2625dac696bcd8101b575cc7651f7c4d14faf9f196a2bedf5b9373b263d4f" CACHE STRING "SHA256 hash of the IlmBase archive.") include(dep_ilmbase) set(ZLIB_VERSION "1.2.11") set(ZLIB_URL "https://www.zlib.net/zlib-${ZLIB_VERSION}.tar.gz" CACHE STRING "URL of the zlib archive.") - set(ZLIB_HASH "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1" + set(ZLIB_HASH "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1" CACHE STRING "SHA256 hash of the zlib archive.") include(dep_zlib) - set(BOOST_VERSION "1.77.0") + set(BOOST_VERSION "1.78.0") string(REPLACE "." "_" BOOST_FILE_BASE "${BOOST_VERSION}") set(BOOST_BASE_URL "https://boostorg.jfrog.io/artifactory/main/release/${BOOST_VERSION}/source/boost") set(_BOOST_URL "${BOOST_BASE_URL}_${BOOST_FILE_BASE}.tar.gz") - set(_BOOST_HASH "5347464af5b14ac54bb945dc68f1dd7c56f0dad7262816b956138fc53bcc0131") + set(_BOOST_HASH "94ced8b72956591c4775ae2207a9763d3600b30d9d7446562c552f0a14a63be7") set(BOOST_URL "${_BOOST_URL}" CACHE STRING "URL of the boost archive.") set(BOOST_HASH "${_BOOST_HASH}" CACHE STRING "SHA256 hash of the boost archive.") include(dep_boost) diff --git a/testing/external/catch.hpp b/testing/external/catch.hpp index 7e706f94..db1fed3b 100644 --- a/testing/external/catch.hpp +++ b/testing/external/catch.hpp @@ -1,9 +1,9 @@ /* - * Catch v2.13.7 - * Generated: 2021-07-28 20:29:27.753164 + * Catch v2.13.8 + * Generated: 2022-01-03 21:20:09.589503 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,7 +15,7 @@ #define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MINOR 13 -#define CATCH_VERSION_PATCH 7 +#define CATCH_VERSION_PATCH 8 #ifdef __clang__ # pragma clang system_header @@ -240,9 +240,6 @@ namespace Catch { // Visual C++ #if defined(_MSC_VER) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) - // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) @@ -251,13 +248,18 @@ namespace Catch { # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif +# if !defined(__clang__) // Handle Clang masquerading for msvc + // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(__clang__) // Handle Clang masquerading for msvc # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR # endif // MSVC_TRADITIONAL + +// Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop` +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) # endif // __clang__ #endif // _MSC_VER @@ -1010,34 +1012,34 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) #endif #endif @@ -1050,7 +1052,7 @@ struct AutoReg : NonCopyable { CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ - INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ @@ -1072,7 +1074,7 @@ struct AutoReg : NonCopyable { CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ - INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) + INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ @@ -1113,18 +1115,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \ @@ -1162,18 +1164,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T,__VA_ARGS__) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T,__VA_ARGS__) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\ @@ -1204,7 +1206,7 @@ struct AutoReg : NonCopyable { static void TestFunc() #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \ - INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, TmplList ) + INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, TmplList ) #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ @@ -1237,18 +1239,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\ @@ -1289,18 +1291,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \ @@ -1334,7 +1336,7 @@ struct AutoReg : NonCopyable { void TestName::test() #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \ - INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, TmplList ) + INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, TmplList ) // end catch_test_registry.h // start catch_capture.hpp @@ -3091,7 +3093,7 @@ namespace Detail { Approx operator-() const; template ::value>::type> - Approx operator()( T const& value ) { + Approx operator()( T const& value ) const { Approx approx( static_cast(value) ); approx.m_epsilon = m_epsilon; approx.m_margin = m_margin; @@ -4163,7 +4165,7 @@ namespace Generators { if (!m_predicate(m_generator.get())) { // It might happen that there are no values that pass the // filter. In that case we throw an exception. - auto has_initial_value = next(); + auto has_initial_value = nextImpl(); if (!has_initial_value) { Catch::throw_exception(GeneratorException("No valid value found in filtered generator")); } @@ -4175,6 +4177,11 @@ namespace Generators { } bool next() override { + return nextImpl(); + } + + private: + bool nextImpl() { bool success = m_generator.next(); if (!success) { return false; @@ -15380,7 +15387,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 13, 7, "", 0 ); + static Version version( 2, 13, 8, "", 0 ); return version; } @@ -17648,9 +17655,9 @@ int main (int argc, char * const argv[]) { #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) #define CATCH_BENCHMARK(...) \ - INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) + INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) #define CATCH_BENCHMARK_ADVANCED(name) \ - INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name) + INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) #endif // CATCH_CONFIG_ENABLE_BENCHMARKING // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required @@ -17752,9 +17759,9 @@ int main (int argc, char * const argv[]) { #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) #define BENCHMARK(...) \ - INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) + INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) #define BENCHMARK_ADVANCED(name) \ - INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name) + INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) #endif // CATCH_CONFIG_ENABLE_BENCHMARKING using Catch::Detail::Approx; @@ -17801,8 +17808,8 @@ using Catch::Detail::Approx; #define CATCH_WARN( msg ) (void)(0) #define CATCH_CAPTURE( msg ) (void)(0) -#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) #define CATCH_SECTION( ... ) @@ -17811,7 +17818,7 @@ using Catch::Detail::Approx; #define CATCH_FAIL_CHECK( ... ) (void)(0) #define CATCH_SUCCEED( ... ) (void)(0) -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) @@ -17834,8 +17841,8 @@ using Catch::Detail::Approx; #endif // "BDD-style" convenience wrappers -#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) #define CATCH_GIVEN( desc ) #define CATCH_AND_GIVEN( desc ) #define CATCH_WHEN( desc ) @@ -17885,8 +17892,8 @@ using Catch::Detail::Approx; #define WARN( msg ) (void)(0) #define CAPTURE( msg ) (void)(0) -#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #define METHOD_AS_TEST_CASE( method, ... ) #define REGISTER_TEST_CASE( Function, ... ) (void)(0) #define SECTION( ... ) @@ -17894,7 +17901,7 @@ using Catch::Detail::Approx; #define FAIL( ... ) (void)(0) #define FAIL_CHECK( ... ) (void)(0) #define SUCCEED( ... ) (void)(0) -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) @@ -17924,8 +17931,8 @@ using Catch::Detail::Approx; #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) // "BDD-style" convenience wrappers -#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) -#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ) ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) #define GIVEN( desc ) #define AND_GIVEN( desc ) From 5d2632d24b0739d295a6f2dba4f1039e5508335a Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Fri, 11 Feb 2022 11:07:35 -0700 Subject: [PATCH 21/25] superbuild: update to rkcommon v1.9.0 and Embree v3.13.3. --- superbuild/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/superbuild/CMakeLists.txt b/superbuild/CMakeLists.txt index e020e660..ca72dc0a 100644 --- a/superbuild/CMakeLists.txt +++ b/superbuild/CMakeLists.txt @@ -153,10 +153,10 @@ endif() option(BUILD_RKCOMMON "Build rkcommon or search in environment?" ON) if (BUILD_RKCOMMON) - set(RKCOMMON_VERSION "v1.8.0" CACHE STRING "rkcommon version to download") + set(RKCOMMON_VERSION "v1.9.0" CACHE STRING "rkcommon version to download") set(RKCOMMON_URL "https://github.com/ospray/rkcommon/archive/${RKCOMMON_VERSION}.zip" CACHE STRING "URL of the rkcommon archive.") - set(RKCOMMON_HASH "d9593de25a9b705d7d56f53d655c71901a25be21d88aa493d39d2d6e61ed7393" + set(RKCOMMON_HASH "54ef58226b5f2b6eb80091d806b94d563ce748a6c8d04db7836c20945fd99929" CACHE STRING "SHA256 hash of the rkcommon archive.") include(dep_rkcommon) endif() @@ -166,23 +166,23 @@ endif() option(BUILD_EMBREE "Build Intel Embree or search in environment?" ON) option(BUILD_EMBREE_FROM_SOURCE "Build Embree from source or use pre-built version? (Only used when BUILD_EMBREE=ON)" ON) if (BUILD_EMBREE) - set(EMBREE_VERSION "v3.13.2" CACHE STRING "Embree version to download") + set(EMBREE_VERSION "v3.13.3" CACHE STRING "Embree version to download") if (BUILD_EMBREE_FROM_SOURCE) set(_EMBREE_URL "https://github.com/embree/embree/archive/${EMBREE_VERSION}.zip") - set(_EMBREE_HASH "eaa7a8ecd78594fb9eed75b2abbabd30dd68afb49556c250799daaeec016237c") + set(_EMBREE_HASH "e98db1522d377a1d47c04ff7db29ccb4207412751c33cb756de32b20ae66e9b1") else() # Embree binary package URLs do not use the "v" prefix string(REPLACE "v" "" EMBREE_VERSION_NUMBER ${EMBREE_VERSION}) set(EMBREE_BASE_URL "https://github.com/embree/embree/releases/download/${EMBREE_VERSION}") if (APPLE) set(_EMBREE_URL "${EMBREE_BASE_URL}/embree-${EMBREE_VERSION_NUMBER}.x86_64.macosx.zip") - set(_EMBREE_HASH "6e9442e516cd54c2e7f6454c90fb8cda5721d76a14d29880ffa387820a486762") + set(_EMBREE_HASH "79f2e56b4697f833be9b5088bea9c7ce22119adacaf09390e23a7140f6383fd9") elseif (WIN32) set(_EMBREE_URL "${EMBREE_BASE_URL}/embree-${EMBREE_VERSION_NUMBER}.x64.vc14.windows.zip") - set(_EMBREE_HASH "76570583a3d3e78f74b3cde2b0bbff8b0cc527959cc68b9e501b295e3aa7a960") + set(_EMBREE_HASH "1decef1ab8d0f5b2b4ef59bf70b303da05d0fe8d741d0e15bacaccd144055821") else() set(_EMBREE_URL "${EMBREE_BASE_URL}/embree-${EMBREE_VERSION_NUMBER}.x86_64.linux.tar.gz") - set(_EMBREE_HASH "8142c1fa0e8e89e279581e873f558b008a3d49b9b1e0091393e50377bcc52639") + set(_EMBREE_HASH "0c5884a6d3dffa082c329327276b91cc686ae0374e91a4c2cbea8cf6f7ddfeb4") endif() endif() set(EMBREE_URL "${_EMBREE_URL}" CACHE STRING "URL of the Embree source archive.") From 01e5b5b4af53c92eaa458849c1684e1f1e22a1a4 Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Mon, 31 Jan 2022 15:28:49 -0700 Subject: [PATCH 22/25] structuredRegular: support cell-centered or vertex-centered data via the `cellCentered` parameter; the default is still vertex-centered. --- doc/api.md | 27 +++++++++++-------- .../devices/cpu/volume/vdb/DenseVdbVolume.cpp | 5 ++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/doc/api.md b/doc/api.md index 53926203..75166c41 100644 --- a/doc/api.md +++ b/doc/api.md @@ -440,11 +440,12 @@ Finally, the value range of the volume for a given attribute can be queried: ### Structured Volumes Structured volumes only need to store the values of the samples, because their -addresses in memory can be easily computed from a 3D position. The dimensions -for all structured volume types are in units of vertices, not cells. For -example, a volume with dimensions $(x, y, z)$ will have $(x-1, y-1, z-1)$ cells -in each dimension. Voxel data provided is assumed vertex-centered, so $x*y*z$ -values must be provided. +addresses in memory can be easily computed from a 3D position. Data can be +provided either per cell or per vertex (the default), selectable via the +`cellCentered` parameter. This parameter also affects the interpretation of +the volume's dimensions, which will be in units of cells or vertices, +respectively. A volume with $(x, y, z)$ vertices will have $(x-1, y-1, z-1)$ +cells. #### Structured Regular Volumes @@ -456,10 +457,10 @@ table below. --------- -------------------------------- ----------------------------- --------------------------------------- Type Name Default Description --------- -------------------------------- ----------------------------- --------------------------------------- - vec3i dimensions number of voxels in each + vec3i dimensions number of values in each dimension $(x, y, z)$ - VKLData data VKLData object(s) of voxel data, + VKLData data VKLData object(s) of volume data, VKLData[] supported types are: `VKL_UCHAR` @@ -478,6 +479,9 @@ table below. through passing an array of VKLData objects. + bool cellCentered false indicates if data is provided per cell + (true) or per vertex (false) + vec3f gridOrigin $(0, 0, 0)$ origin of the grid in object space vec3f gridSpacing $(1, 1, 1)$ size of the grid cells in object space @@ -558,7 +562,8 @@ Structured spherical volumes are also supported, which are created by passing a type string of `"structuredSpherical"` to `vklNewVolume`. The grid dimensions and parameters are defined in terms of radial distance ($r$), inclination angle ($\theta$), and azimuthal angle ($\phi$), conforming with the ISO convention for -spherical coordinate systems. The coordinate system and parameters understood by +spherical coordinate systems. Structured spherical volumes currently only +support vertex-centered data. The coordinate system and parameters understood by structured spherical volumes are summarized below. ![Structured spherical volume coordinate system: radial distance ($r$), inclination angle ($\theta$), and azimuthal angle ($\phi$).][imgStructuredSphericalCoords] @@ -828,9 +833,9 @@ VDB leaf nodes are implicit in Open VKL: they are stored as pointers to user-pro ![Structure of `"vdb"` volumes in the default configuration][imgVdbStructure] -VDB volumes interpret input data as constant cells (which are then potentially filtered). -This is in contrast to `structuredRegular` volumes, which have a vertex-centered -interpretation. +VDB volumes interpret input data as constant cells (which are then potentially +filtered). This is in contrast to `structuredRegular` volumes, which can have +either a vertex-centered or cell-centered interpretation. The VDB implementation in Open VKL follows the following goals: diff --git a/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp b/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp index 79c42297..574e7e54 100644 --- a/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp +++ b/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp @@ -23,9 +23,8 @@ namespace openvkl { this->denseTemporallyUnstructuredIndices = temporallyUnstructuredIndices; this->denseTemporallyUnstructuredTimes = temporallyUnstructuredTimes; - // for now, always assume vertex-centered representation to match legacy - // structuredRegular data interpretation - this->constantCellData = false; + this->constantCellData = + this->template getParam("cellCentered", false); VdbVolume::commit(); } From a552044d780fe698f703a5d379eaba35755e494b Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Fri, 4 Feb 2022 15:55:52 -0700 Subject: [PATCH 23/25] structuredRegular: add indexOrigin parameter which applies an index-space vec3i translation. --- doc/api.md | 6 ++++++ openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp | 5 ++++- openvkl/devices/cpu/volume/vdb/DenseVdbVolume.h | 3 ++- openvkl/devices/cpu/volume/vdb/VdbQueryVoxelDense.ih | 4 +--- openvkl/devices/cpu/volume/vdb/VdbSampler.ispc | 7 +++---- .../cpu/volume/vdb/VdbSampler_traverseAndSample.ih | 12 +++++------- .../devices/cpu/volume/vdb/VdbSampler_trilinear.ih | 8 +++++--- openvkl/devices/cpu/volume/vdb/VdbVolume.cpp | 9 ++++++--- openvkl/devices/cpu/volume/vdb/VdbVolume.h | 1 + 9 files changed, 33 insertions(+), 22 deletions(-) diff --git a/doc/api.md b/doc/api.md index 75166c41..3acf94be 100644 --- a/doc/api.md +++ b/doc/api.md @@ -494,6 +494,12 @@ table below. `gridOrigin` and `gridSpacing`, if provided. + vec3i indexOrigin $(0, 0, 0)$ Defines the index space origin of the + volume. This translation is applied + before any (`gridOrigin`, + `gridSpacing`) or `indexToObject` + transformation. + uint32 temporalFormat `VKL_TEMPORAL_FORMAT_CONSTANT` The temporal format for this volume. Use `VKLTemporalFormat` for named constants. diff --git a/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp b/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp index 574e7e54..05a3c246 100644 --- a/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp +++ b/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.cpp @@ -16,6 +16,7 @@ namespace openvkl { this->dense = true; this->denseDimensions = dimensions; + this->denseIndexOrigin = indexOrigin; this->denseData = attributesData; this->denseTemporalFormat = temporalFormat; this->denseTemporallyStructuredNumTimesteps = @@ -75,7 +76,7 @@ namespace openvkl { std::vector leafOrigins; for (const auto &ijk : mis) { - leafOrigins.push_back(ijk * VKL_VDB_RES_LEAF); + leafOrigins.push_back(ijk * VKL_VDB_RES_LEAF + this->indexOrigin); } assert(leafOrigins.size() == this->numLeaves); @@ -109,6 +110,8 @@ namespace openvkl { gridOrigin = this->template getParam("gridOrigin", vec3f(0.f)); gridSpacing = this->template getParam("gridSpacing", vec3f(1.f)); + indexOrigin = this->template getParam("indexOrigin", vec3i(0)); + attributesData.clear(); if (this->template hasParamDataT("data")) { diff --git a/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.h b/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.h index e10db203..889d68a4 100644 --- a/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.h +++ b/openvkl/devices/cpu/volume/vdb/DenseVdbVolume.h @@ -1,4 +1,4 @@ -// Copyright 2021 Intel Corporation +// Copyright 2021-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -26,6 +26,7 @@ namespace openvkl { vec3i dimensions; vec3f gridOrigin; vec3f gridSpacing; + vec3i indexOrigin; std::vector> attributesData; VKLTemporalFormat temporalFormat; int temporallyStructuredNumTimesteps; diff --git a/openvkl/devices/cpu/volume/vdb/VdbQueryVoxelDense.ih b/openvkl/devices/cpu/volume/vdb/VdbQueryVoxelDense.ih index 04d1438a..75aefde2 100644 --- a/openvkl/devices/cpu/volume/vdb/VdbQueryVoxelDense.ih +++ b/openvkl/devices/cpu/volume/vdb/VdbQueryVoxelDense.ih @@ -1,4 +1,4 @@ -// Copyright 2021 Intel Corporation +// Copyright 2021-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -128,8 +128,6 @@ inline void VdbIterator_queryVoxel_dense( desc.level = queryDepth; - assert(grid->rootOrigin.x == 0 && grid->rootOrigin.y == 0 && - grid->rootOrigin.z == 0); const vec3ui domainOffset = make_vec3ui(x, y, z); if (!VdbIterator_isInDomain(grid->activeSize, domainOffset)) { diff --git a/openvkl/devices/cpu/volume/vdb/VdbSampler.ispc b/openvkl/devices/cpu/volume/vdb/VdbSampler.ispc index 137df795..79fe85e7 100644 --- a/openvkl/devices/cpu/volume/vdb/VdbSampler.ispc +++ b/openvkl/devices/cpu/volume/vdb/VdbSampler.ispc @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Intel Corporation +// Copyright 2019-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include @@ -502,9 +502,8 @@ export void EXPORT_UNIQUE(VdbSampler_computeValueRange, // voxel is only needed for non-dense case if (grid->dense) { - assert(grid->rootOrigin.x == 0 && grid->rootOrigin.y == 0 && - grid->rootOrigin.z == 0); - domainOffset = make_vec3ui(nodeOrigin.x, nodeOrigin.y, nodeOrigin.z); + domainOffset = + VdbSampler_toDomainOffset(nodeOrigin, grid->rootOrigin); } else { VdbSampler_traverse(&sampler, nodeOrigin, voxel, domainOffset); } diff --git a/openvkl/devices/cpu/volume/vdb/VdbSampler_traverseAndSample.ih b/openvkl/devices/cpu/volume/vdb/VdbSampler_traverseAndSample.ih index d3be7a18..2ecba666 100644 --- a/openvkl/devices/cpu/volume/vdb/VdbSampler_traverseAndSample.ih +++ b/openvkl/devices/cpu/volume/vdb/VdbSampler_traverseAndSample.ih @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Intel Corporation +// Copyright 2019-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -304,10 +304,9 @@ inline uniform float VdbSampler_traverseAndSample_dense( assert(sampler); assert(sampler->grid); assert(sampler->grid->dense); - assert(sampler->grid->rootOrigin.x == 0 && sampler->grid->rootOrigin.y == 0 && - sampler->grid->rootOrigin.z == 0); - const uniform vec3ui domainOffset = make_vec3ui(ic); + const uniform vec3ui domainOffset = + VdbSampler_toDomainOffset(ic, sampler->grid->rootOrigin); if (VdbSampler_isInDomain(sampler->grid->activeSize, domainOffset)) { return sampler->denseLeafSample_uniform[attributeIndex]( sampler->grid, attributeIndex, domainOffset, time); @@ -324,10 +323,9 @@ inline float VdbSampler_traverseAndSample_dense( assert(sampler); assert(sampler->grid); assert(sampler->grid->dense); - assert(sampler->grid->rootOrigin.x == 0 && sampler->grid->rootOrigin.y == 0 && - sampler->grid->rootOrigin.z == 0); - const vec3ui domainOffset = make_vec3ui(ic); + const vec3ui domainOffset = + VdbSampler_toDomainOffset(ic, sampler->grid->rootOrigin); if (VdbSampler_isInDomain(sampler->grid->activeSize, domainOffset)) { return sampler->denseLeafSample_varying[attributeIndex]( sampler->grid, attributeIndex, domainOffset, time); diff --git a/openvkl/devices/cpu/volume/vdb/VdbSampler_trilinear.ih b/openvkl/devices/cpu/volume/vdb/VdbSampler_trilinear.ih index 83b1226b..ab6162b4 100644 --- a/openvkl/devices/cpu/volume/vdb/VdbSampler_trilinear.ih +++ b/openvkl/devices/cpu/volume/vdb/VdbSampler_trilinear.ih @@ -1,4 +1,4 @@ -// Copyright 2021 Intel Corporation +// Copyright 2021-2022 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once @@ -187,7 +187,8 @@ inline void VdbSampler_computeVoxelValuesTrilinear_dense( // if the entire domain of the trilinear interpolation is in bounds, and other // constraints are satisfied, we can take a fast path. - const vec3ui domainOffset = make_vec3ui(ic.x, ic.y, ic.z); + const vec3ui domainOffset = + VdbSampler_toDomainOffset(ic, sampler->grid->rootOrigin); if (sampler->grid->denseTemporalFormat == VKL_TEMPORAL_FORMAT_CONSTANT && safe_32bit_indexing(sampler->grid->denseData[attributeIndex]) && @@ -248,7 +249,8 @@ inline void VdbSampler_computeVoxelValuesTrilinear_dense( // if the entire domain of the trilinear interpolation is in bounds, and other // constraints are satisfied, we can take a fast path. - const uniform vec3ui domainOffset = make_vec3ui(ic.x, ic.y, ic.z); + const uniform vec3ui domainOffset = + VdbSampler_toDomainOffset(ic, sampler->grid->rootOrigin); if (sampler->grid->denseTemporalFormat == VKL_TEMPORAL_FORMAT_CONSTANT && safe_32bit_indexing(sampler->grid->denseData[attributeIndex]) && diff --git a/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp b/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp index e05e16fe..3df2dc6f 100644 --- a/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp +++ b/openvkl/devices/cpu/volume/vdb/VdbVolume.cpp @@ -701,15 +701,18 @@ namespace openvkl { box3f indexBoundingBox; if (grid->dense) { - grid->rootOrigin = vec3i(0); + grid->rootOrigin = denseIndexOrigin; grid->activeSize = grid->denseDimensions; if (constantCellData) { - indexBoundingBox = box3f(vec3f(0.f), vec3f(grid->denseDimensions)); + indexBoundingBox = + box3f(vec3f(grid->rootOrigin), + vec3f(grid->rootOrigin + grid->denseDimensions)); } else { indexBoundingBox = - box3f(vec3f(0.f), vec3f(grid->denseDimensions - 1)); + box3f(vec3f(grid->rootOrigin), + vec3f(grid->rootOrigin + grid->denseDimensions - 1)); } } else { if (!constantCellData) { diff --git a/openvkl/devices/cpu/volume/vdb/VdbVolume.h b/openvkl/devices/cpu/volume/vdb/VdbVolume.h index 8ca4f27a..8a1cbda7 100644 --- a/openvkl/devices/cpu/volume/vdb/VdbVolume.h +++ b/openvkl/devices/cpu/volume/vdb/VdbVolume.h @@ -179,6 +179,7 @@ namespace openvkl { // populated for dense volumes only on commit bool dense{false}; vec3i denseDimensions; + vec3i denseIndexOrigin; std::vector> denseData; VKLTemporalFormat denseTemporalFormat; int denseTemporallyStructuredNumTimesteps; From 6383a58c906d92737d265c4539873d7eee721dbb Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Mon, 31 Jan 2022 13:24:13 -0700 Subject: [PATCH 24/25] add VDB / structuredRegular equivalence tests, which use the new cellCentered and indexOrigin structuredRegular parameters. --- testing/apps/CMakeLists.txt | 1 + testing/apps/tests/vdb_volume_dense.cpp | 400 ++++++++++++++++++++++++ 2 files changed, 401 insertions(+) create mode 100644 testing/apps/tests/vdb_volume_dense.cpp diff --git a/testing/apps/CMakeLists.txt b/testing/apps/CMakeLists.txt index 1f777571..50301716 100644 --- a/testing/apps/CMakeLists.txt +++ b/testing/apps/CMakeLists.txt @@ -137,6 +137,7 @@ if (BUILD_TESTING) tests/vdb_volume_multi.cpp tests/vdb_volume_motion_blur.cpp tests/vdb_volume_inner_node_observer.cpp + tests/vdb_volume_dense.cpp tests/particle_volume_sampling.cpp tests/particle_volume_gradients.cpp tests/particle_volume_value_range.cpp diff --git a/testing/apps/tests/vdb_volume_dense.cpp b/testing/apps/tests/vdb_volume_dense.cpp new file mode 100644 index 00000000..1b5ce762 --- /dev/null +++ b/testing/apps/tests/vdb_volume_dense.cpp @@ -0,0 +1,400 @@ +// Copyright 2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include +#include "../../external/catch.hpp" +#include "openvkl_testing.h" +#include "rkcommon/array3D/for_each.h" +#include "rkcommon/utility/getEnvVar.h" +#include "sampling_utility.h" + +#if defined(_MSC_VER) +#include // _malloca +#endif + +inline static void requireEqualsHelper(const float v1, const float v2) +{ + if (std::isnan(v1)) { + REQUIRE((std::isnan(v1) && std::isnan(v2))); + } else { +#ifdef __OPTIMIZE__ + // with certain optimizations, for example -ffp-contract=fast, we can see + // some numerical differences due to differing code paths and use of fma, + // etc.; so allow a tolerance here for those cases + REQUIRE(v1 == Approx(v2).margin(1e-3f)); +#else + REQUIRE(v1 == v2); +#endif + } +} + +#ifdef OPENVKL_UTILITY_VDB_OPENVDB_ENABLED +#include + +static VKLVolume vdbToStructuredRegular(openvdb::FloatGrid::Ptr grid) +{ + auto _dims = grid->evalActiveVoxelDim(); + const vec3i dimensions = vec3i(_dims.x() - 1, _dims.y() - 1, _dims.z() - 1); + + auto _bbox = grid->evalActiveVoxelBoundingBox(); + const vec3i indexOrigin = + vec3i(_bbox.min().x(), _bbox.min().y(), _bbox.min().z()); + + std::vector voxels; + voxels.reserve(rkcommon::array3D::longProduct(dimensions)); + + auto accessor = grid->getAccessor(); + + for (size_t k = 0; k < dimensions.z; k++) { + for (size_t j = 0; j < dimensions.y; j++) { + for (size_t i = 0; i < dimensions.x; i++) { + openvdb::Coord xyz( + indexOrigin.x + i, indexOrigin.y + j, indexOrigin.z + k); + float value = accessor.getValue(xyz); + voxels.push_back(value); + } + } + } + + if (rkcommon::array3D::longProduct(dimensions) != voxels.size()) { + throw std::runtime_error( + "inconsistent number of voxels in VKLVolume conversion"); + } + + VKLVolume vklVolumeStructured = + vklNewVolume(getOpenVKLDevice(), "structuredRegular"); + + vklSetBool(vklVolumeStructured, "cellCentered", true); + + vklSetFloat(vklVolumeStructured, "background", 0.f); + + vklSetVec3i(vklVolumeStructured, + "dimensions", + dimensions.x, + dimensions.y, + dimensions.z); + + vklSetVec3i(vklVolumeStructured, + "indexOrigin", + indexOrigin.x, + indexOrigin.y, + indexOrigin.z); + + const auto &indexToObject = grid->transform().baseMap(); + if (!indexToObject->isLinear()) + throw std::runtime_error( + "OpenVKL only supports linearly transformed volumes"); + + const auto &ri2o = indexToObject->getAffineMap()->getMat4(); + const auto *i2o = ri2o.asPointer(); + AffineSpace3f openvdbIndexToObject; + openvdbIndexToObject.l = LinearSpace3f(vec3f(i2o[0], i2o[1], i2o[2]), + vec3f(i2o[4], i2o[5], i2o[6]), + vec3f(i2o[8], i2o[9], i2o[10])); + openvdbIndexToObject.p = vec3f(i2o[12], i2o[13], i2o[14]); + + vklSetParam(vklVolumeStructured, + "indexToObject", + VKL_AFFINE3F, + &openvdbIndexToObject); + + VKLData data = + vklNewData(getOpenVKLDevice(), voxels.size(), VKL_FLOAT, voxels.data()); + vklSetData(vklVolumeStructured, "data", data); + vklRelease(data); + + vklCommit(vklVolumeStructured); + + return vklVolumeStructured; +} +#endif + +static void bounding_box_equivalence(VKLVolume vklVolume1, VKLVolume vklVolume2) +{ + vkl_box3f bb1 = vklGetBoundingBox(vklVolume1); + vkl_box3f bb2 = vklGetBoundingBox(vklVolume2); + + REQUIRE(bb1.lower.x == bb2.lower.x); + REQUIRE(bb1.lower.y == bb2.lower.y); + REQUIRE(bb1.lower.z == bb2.lower.z); + + REQUIRE(bb1.upper.x == bb2.upper.x); + REQUIRE(bb1.upper.y == bb2.upper.y); + REQUIRE(bb1.upper.z == bb2.upper.z); +} + +static void sampling_gradient_equivalence(VKLVolume vklVolume1, + VKLVolume vklVolume2) +{ + // we'll test under different filter modes + const std::vector filters = { + VKL_FILTER_NEAREST, VKL_FILTER_TRILINEAR, VKL_FILTER_TRICUBIC}; + + for (const auto &filter : filters) { + VKLSampler sampler1 = vklNewSampler(vklVolume1); + vklSetInt(sampler1, "filter", filter); + vklCommit(sampler1); + + VKLSampler sampler2 = vklNewSampler(vklVolume2); + vklSetInt(sampler2, "filter", filter); + vklCommit(sampler2); + + // assume bounding boxes match + vkl_box3f bbox = vklGetBoundingBox(vklVolume1); + + std::random_device rd; + std::mt19937 eng(rd()); + + std::uniform_real_distribution distX(bbox.lower.x, bbox.upper.x); + std::uniform_real_distribution distY(bbox.lower.y, bbox.upper.y); + std::uniform_real_distribution distZ(bbox.lower.z, bbox.upper.z); + + const size_t N = 1024; + + for (size_t i = 0; i < N; i++) { + vkl_vec3f oc{distX(eng), distY(eng), distZ(eng)}; + + const float s1 = vklComputeSample(sampler1, &oc); + const float s2 = vklComputeSample(sampler2, &oc); + + requireEqualsHelper(s1, s2); + + const vkl_vec3f g1 = vklComputeGradient(sampler1, &oc); + const vkl_vec3f g2 = vklComputeGradient(sampler2, &oc); + + requireEqualsHelper(g1.x, g2.x); + requireEqualsHelper(g1.y, g2.y); + requireEqualsHelper(g1.z, g2.z); + } + + vklRelease(sampler1); + vklRelease(sampler2); + } +} + +static void iterator_equivalence(VKLVolume vklVolume1, + VKLVolume vklVolume2, + bool matchIntervalsExactly = true) +{ + vkl_range1f range1 = vklGetValueRange(vklVolume1); + vkl_range1f range2 = vklGetValueRange(vklVolume2); + REQUIRE(range1.lower == range2.lower); + REQUIRE(range1.upper == range2.upper); + + std::vector ranges; + ranges.push_back( + vkl_range1f{range1.lower + 0.4f * (range1.upper - range1.lower), + range1.lower + 0.6f * (range1.upper - range1.lower)}); + VKLData rangesData = + vklNewData(getOpenVKLDevice(), ranges.size(), VKL_BOX1F, ranges.data()); + + VKLSampler sampler1 = vklNewSampler(vklVolume1); + vklCommit(sampler1); + + VKLSampler sampler2 = vklNewSampler(vklVolume2); + vklCommit(sampler2); + + VKLIntervalIteratorContext context1 = vklNewIntervalIteratorContext(sampler1); + vklSetData(context1, "valueRanges", rangesData); + vklCommit(context1); + + VKLIntervalIteratorContext context2 = vklNewIntervalIteratorContext(sampler2); + vklSetData(context2, "valueRanges", rangesData); + vklCommit(context2); + + // assume bounding boxes match + vkl_box3f bbox = vklGetBoundingBox(vklVolume1); + vkl_vec3f center = {0.5f * (bbox.lower.x + bbox.upper.x), + 0.5f * (bbox.lower.y + bbox.upper.y), + 0.5f * (bbox.lower.z + bbox.upper.z)}; + + vkl_vec3f rayOrigin = { + bbox.lower.x - 1.f, bbox.lower.y - 1.f, bbox.lower.z - 1.f}; + vkl_vec3f rayDirection = { + center.x - rayOrigin.x, center.y - rayOrigin.y, center.z - rayOrigin.z}; + vkl_range1f rayTRange = {0.f, inf}; + + // Note: buffer will cease to exist at the end of this scope. +#if defined(_MSC_VER) + // MSVC does not support variable length arrays, but provides a + // safer version of alloca. + char *buffer1 = + static_cast(_malloca(vklGetIntervalIteratorSize(context1))); + char *buffer2 = + static_cast(_malloca(vklGetIntervalIteratorSize(context2))); +#else + char *buffer1 = + static_cast(alloca(vklGetIntervalIteratorSize(context1))); + char *buffer2 = + static_cast(alloca(vklGetIntervalIteratorSize(context2))); +#endif + + size_t numIterations = 0; + + VKLIntervalIterator iterator1 = vklInitIntervalIterator( + context1, &rayOrigin, &rayDirection, &rayTRange, 0.f, buffer1); + + VKLIntervalIterator iterator2 = vklInitIntervalIterator( + context2, &rayOrigin, &rayDirection, &rayTRange, 0.f, buffer2); + + while (true) { + VKLInterval interval1, interval2; + + int result1 = vklIterateInterval(iterator1, &interval1); + int result2 = vklIterateInterval(iterator2, &interval2); + + REQUIRE(result1 == result2); + + if (!result1 || !result2) { + break; + } + + numIterations++; + + if (matchIntervalsExactly) { + requireEqualsHelper(interval1.tRange.lower, interval2.tRange.lower); + requireEqualsHelper(interval1.tRange.upper, interval2.tRange.upper); + + requireEqualsHelper(interval1.valueRange.lower, + interval2.valueRange.lower); + requireEqualsHelper(interval1.valueRange.upper, + interval2.valueRange.upper); + + requireEqualsHelper(interval1.nominalDeltaT, interval2.nominalDeltaT); + } else { + // if we're not matching intervals exactly, we'll only make sure we get at + // least one interval for each iterator / volume + break; + } + } + + REQUIRE(numIterations > 0); + + vklRelease(rangesData); + vklRelease(sampler1); + vklRelease(sampler2); + vklRelease(context1); + vklRelease(context2); +} + +static void test_volume_equivalence(VKLVolume vklVolume1, VKLVolume vklVolume2) +{ + bounding_box_equivalence(vklVolume1, vklVolume2); + sampling_gradient_equivalence(vklVolume1, vklVolume2); +} + +static void test_volume_equivalence_rotation(VKLVolume vklVolume1, + VKLVolume vklVolume2) +{ + // also verify equivalence under rotation + const std::vector axes{ + {1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, 1.f}, {1.f, 1.f, 1.f}}; + + const std::vector anglesDeg{ + 0.f, 30.f, 45.f, 60.f, 90.f, 120.f, 135.f, 150.f, 180.f}; + + const vec3f gridOrigin(-1.f, -2.f, -3.f); + const vec3f gridSpacing(1.f, 2.f, 3.f); + const AffineSpace3f original = + AffineSpace3f::translate(gridOrigin) * AffineSpace3f::scale(gridSpacing); + + for (const auto &axis : axes) { + for (const auto &angleDeg : anglesDeg) { + const AffineSpace3f rot = + original * AffineSpace3f::rotate(axis, angleDeg * M_PI / 180.f); + + vklSetParam(vklVolume1, "indexToObject", VKL_AFFINE3F, &rot); + vklCommit(vklVolume1); + + vklSetParam(vklVolume2, "indexToObject", VKL_AFFINE3F, &rot); + vklCommit(vklVolume2); + + bounding_box_equivalence(vklVolume1, vklVolume2); + sampling_gradient_equivalence(vklVolume1, vklVolume2); + } + } +} + +TEST_CASE("VDB volume dense consistency", "[volume_sampling]") +{ + initializeOpenVKL(); + + SECTION("procedural volumes") + { + const vec3i dimensions(128); + const vec3f gridOrigin(-1.f, -2.f, -3.f); + const vec3f gridSpacing(1.f, 2.f, 3.f); + + std::unique_ptr v1(new WaveletVdbVolumeFloat( + getOpenVKLDevice(), dimensions, gridOrigin, gridSpacing)); + + std::unique_ptr v2( + new WaveletStructuredRegularVolumeFloat( + dimensions, gridOrigin, gridSpacing)); + + VKLVolume vklVolume1 = v1->getVKLVolume(getOpenVKLDevice()); + VKLVolume vklVolume2 = v2->getVKLVolume(getOpenVKLDevice()); + + // VDB volumes use cell-centered data; therefore we must also on the + // structuredRegular volume + vklSetBool(vklVolume2, "cellCentered", true); + vklCommit(vklVolume2); + + test_volume_equivalence(vklVolume1, vklVolume2); + test_volume_equivalence_rotation(vklVolume1, vklVolume2); + + // require exact interval matches for procedurals + iterator_equivalence(vklVolume1, vklVolume2, true); + } + +#ifdef OPENVKL_UTILITY_VDB_OPENVDB_ENABLED + SECTION(".vdb file volumes") + { + std::string vdbFilename = + utility::getEnvVar("OPENVKL_TEST_VDB_FILENAME") + .value_or(std::string("")); + + if (vdbFilename.empty()) { + WARN("OPENVDB_TEST_VDB_FILENAME not set; not running .vdb tests"); + return; + } + + INFO("testing .vdb file: " << vdbFilename); + + // load OpenVDB grid + openvdb::initialize(); + + openvdb::GridBase::Ptr gridBase{nullptr}; + openvdb::FloatGrid::Ptr grid{nullptr}; + + try { + openvdb::io::File file(vdbFilename); + file.open(); + gridBase = file.readGrid("density"); + grid = openvdb::gridPtrCast(gridBase); + file.close(); + } catch (const std::exception &e) { + throw std::runtime_error(e.what()); + } + + // instantiate VKL `vdb` volume + auto openvdbGrid = + openvkl::utility::vdb::OpenVdbFloatGrid(getOpenVKLDevice(), grid); + VKLVolume vklVolume1 = openvdbGrid.createVolume(false); + + vklSetFloat(vklVolume1, "background", 0.f); + vklCommit(vklVolume1); + + // instantiate VKL `structuredRegular` volume + VKLVolume vklVolume2 = vdbToStructuredRegular(grid); + + test_volume_equivalence(vklVolume1, vklVolume2); + + // .vdb files may have combinations of (rootOrigin, indexClippingBounds) + // that cause different tree node layouts, which would impact iterator + // interval boundaries. therefore, don't require exactness in interval + // comparisons here. + iterator_equivalence(vklVolume1, vklVolume2, false); + } +#endif +} From 44579dd6a03aca812660f49076a30270bec9749d Mon Sep 17 00:00:00 2001 From: Greg Johnson Date: Mon, 14 Feb 2022 10:26:29 -0700 Subject: [PATCH 25/25] update changelog for v1.2.0; rebuild README.md. --- CHANGELOG.md | 26 ++++++++++ README.md | 137 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 121 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d28b54c5..c478f472 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,32 @@ Version History --------------- +### Open VKL 1.2.0 + +- Added `vklSetParam()` API function which can set parameters of any supported + type +- Structured regular volumes: + - Added support for cell-centered data via the `cellCentered` parameter; + vertex-centered remains the default + - Added support for more general transformations via the `indexToObject` + parameter + - Added `indexOrigin` parameter which applies an index-space vec3i + translation +- VDB volumes: + - Added `indexClippingBounds` parameter, which can restrict the active + voxel bounding box + - The `indexToObject` parameter can now be provided as a `VKL_AFFINE3F` + - Corrected bounding box computations in `InnerNode` observer +- Particle volumes: + - Now ignoring particles with zero radius +- VDB utility library: added `commit` flag (default true) to volume creation + methods, allowing apps to set additional parameters before first commit +- Examples: + - Added new set of minimal examples, which step through creation of basic + volume and isosurface renderers + - Exposing `intervalResolutionHint` parameter in `vklExamples` application +- Superbuild updates to latest versions of dependencies + ### Open VKL 1.1.0 - vklExamples improvements: asynchronous rendering, multiple viewports, diff --git a/README.md b/README.md index 85360efb..5cd7a874 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Intel® Open Volume Kernel Library -This is release v1.1.0 of Intel® Open VKL. For changes and new features +This is release v1.2.0 of Intel® Open VKL. For changes and new features see the [changelog](CHANGELOG.md). Visit http://www.openvkl.org for more information. @@ -33,6 +33,35 @@ example renderers to demonstrate how to best use the Open VKL API. ## Version History +### Open VKL 1.2.0 + + - Added `vklSetParam()` API function which can set parameters of any + supported type + - Structured regular volumes: + - Added support for cell-centered data via the `cellCentered` + parameter; vertex-centered remains the default + - Added support for more general transformations via the + `indexToObject` parameter + - Added `indexOrigin` parameter which applies an index-space vec3i + translation + - VDB volumes: + - Added `indexClippingBounds` parameter, which can restrict the + active voxel bounding box + - The `indexToObject` parameter can now be provided as a + `VKL_AFFINE3F` + - Corrected bounding box computations in `InnerNode` observer + - Particle volumes: + - Now ignoring particles with zero radius + - VDB utility library: added `commit` flag (default true) to volume + creation methods, allowing apps to set additional parameters before + first commit + - Examples: + - Added new set of minimal examples, which step through creation + of basic volume and isosurface renderers + - Exposing `intervalResolutionHint` parameter in `vklExamples` + application + - Superbuild updates to latest versions of dependencies + ### Open VKL 1.1.0 - vklExamples improvements: asynchronous rendering, multiple @@ -576,8 +605,7 @@ and `vklNewVolume`. In general, modifiable parameters to objects are modified using `vklSet...` functions based on the type of the parameter being set. The -parameter name is passed as a string. Below are all variants of -`vklSet...`. +parameter name is passed as a string. Below are variants of `vklSet...`. ``` cpp void vklSetBool(VKLObject object, const char *name, int b); @@ -590,6 +618,21 @@ void vklSetString(VKLObject object, const char *name, const char *s); void vklSetVoidPtr(VKLObject object, const char *name, void *v); ``` +A more generic parameter setter is also available, which allows setting +parameters beyond the explicit types above: + +``` cpp +void vklSetParam(VKLObject object, + const char *name, + VKLDataType dataType, + const void *mem); +``` + +Note that `mem` must always be a pointer *to* the object, otherwise +accidental type casting can occur. This is especially true for pointer +types (`VKL_VOID_PTR` and `VKLObject` handles), as they will implicitly +cast to `void\ *`, but be incorrectly interpreted. + After parameters have been set, `vklCommit` must be called on the object to make them take effect. @@ -763,11 +806,12 @@ vkl_range1f vklGetValueRange(VKLVolume volume, unsigned int attributeIndex); ### Structured Volumes Structured volumes only need to store the values of the samples, because -their addresses in memory can be easily computed from a 3D position. The -dimensions for all structured volume types are in units of vertices, not -cells. For example, a volume with dimensions \((x, y, z)\) will have -\((x-1, y-1, z-1)\) cells in each dimension. Voxel data provided is -assumed vertex-centered, so \(x*y*z\) values must be provided. +their addresses in memory can be easily computed from a 3D position. +Data can be provided either per cell or per vertex (the default), +selectable via the `cellCentered` parameter. This parameter also affects +the interpretation of the volume’s dimensions, which will be in units of +cells or vertices, respectively. A volume with \((x, y, z)\) vertices +will have \((x-1, y-1, z-1)\) cells. #### Structured Regular Volumes @@ -776,24 +820,27 @@ by passing a type string of `"structuredRegular"` to `vklNewVolume`. The parameters understood by structured regular volumes are summarized in the table below. -| Type | Name | Default | Description | -| :-------------------- | :------------------------------- | :----------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| vec3i | dimensions | | number of voxels in each dimension \((x, y, z)\) | -| VKLData VKLData\[\] | data | | VKLData object(s) of voxel data, supported types are: | -| | | | `VKL_UCHAR` | -| | | | `VKL_SHORT` | -| | | | `VKL_USHORT` | -| | | | `VKL_HALF` | -| | | | `VKL_FLOAT` | -| | | | `VKL_DOUBLE` | -| | | | Multiple attributes are supported through passing an array of VKLData objects. | -| vec3f | gridOrigin | \((0, 0, 0)\) | origin of the grid in object space | -| vec3f | gridSpacing | \((1, 1, 1)\) | size of the grid cells in object space | -| uint32 | temporalFormat | `VKL_TEMPORAL_FORMAT_CONSTANT` | The temporal format for this volume. Use `VKLTemporalFormat` for named constants. Structured regular volumes support `VKL_TEMPORAL_FORMAT_CONSTANT`, `VKL_TEMPORAL_FORMAT_STRUCTURED`, and `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | -| int | temporallyStructuredNumTimesteps | | For temporally structured variation, number of timesteps per voxel. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_STRUCTURED`. | -| uint32\[\] uint64\[\] | temporallyUnstructuredIndices | | For temporally unstructured variation, indices to `data` time series beginning per voxel. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | -| float\[\] | temporallyUnstructuredTimes | | For temporally unstructured variation, time values corresponding to values in `data`. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | -| float\[\] | background | `VKL_BACKGROUND_UNDEFINED` | For each attribute, the value that is returned when sampling an undefined region outside the volume domain. | +| Type | Name | Default | Description | +| :-------------------- | :------------------------------- | :--------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| vec3i | dimensions | | number of values in each dimension \((x, y, z)\) | +| VKLData VKLData\[\] | data | | VKLData object(s) of volume data, supported types are: | +| | | | `VKL_UCHAR` | +| | | | `VKL_SHORT` | +| | | | `VKL_USHORT` | +| | | | `VKL_HALF` | +| | | | `VKL_FLOAT` | +| | | | `VKL_DOUBLE` | +| | | | Multiple attributes are supported through passing an array of VKLData objects. | +| bool | cellCentered | false | indicates if data is provided per cell (true) or per vertex (false) | +| vec3f | gridOrigin | \((0, 0, 0)\) | origin of the grid in object space | +| vec3f | gridSpacing | \((1, 1, 1)\) | size of the grid cells in object space | +| affine3f | indexToObject | 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 | Defines the transformation from index space to object space. In index space, the grid is an axis-aligned regular grid, and grid cells have size (1,1,1). This parameter takes precedence over `gridOrigin` and `gridSpacing`, if provided. | +| vec3i | indexOrigin | \((0, 0, 0)\) | Defines the index space origin of the volume. This translation is applied before any (`gridOrigin`, `gridSpacing`) or `indexToObject` transformation. | +| uint32 | temporalFormat | `VKL_TEMPORAL_FORMAT_CONSTANT` | The temporal format for this volume. Use `VKLTemporalFormat` for named constants. Structured regular volumes support `VKL_TEMPORAL_FORMAT_CONSTANT`, `VKL_TEMPORAL_FORMAT_STRUCTURED`, and `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | +| int | temporallyStructuredNumTimesteps | | For temporally structured variation, number of timesteps per voxel. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_STRUCTURED`. | +| uint32\[\] uint64\[\] | temporallyUnstructuredIndices | | For temporally unstructured variation, indices to `data` time series beginning per voxel. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | +| float\[\] | temporallyUnstructuredTimes | | For temporally unstructured variation, time values corresponding to values in `data`. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | +| float\[\] | background | `VKL_BACKGROUND_UNDEFINED` | For each attribute, the value that is returned when sampling an undefined region outside the volume domain. | Configuration parameters for structured regular (`"structuredRegular"`) volumes. @@ -829,9 +876,10 @@ Structured spherical volumes are also supported, which are created by passing a type string of `"structuredSpherical"` to `vklNewVolume`. The grid dimensions and parameters are defined in terms of radial distance (\(r\)), inclination angle (\(\theta\)), and azimuthal angle (\(\phi\)), -conforming with the ISO convention for spherical coordinate systems. The -coordinate system and parameters understood by structured spherical -volumes are summarized below. +conforming with the ISO convention for spherical coordinate systems. +Structured spherical volumes currently only support vertex-centered +data. The coordinate system and parameters understood by structured +spherical volumes are summarized below. ![Structured spherical volume coordinate system: radial distance (\(r\)), inclination angle (\(\theta\)), and azimuthal angle @@ -1045,7 +1093,8 @@ configuration](https://openvkl.github.io/images/vdb_structure.png) VDB volumes interpret input data as constant cells (which are then potentially filtered). This is in contrast to `structuredRegular` -volumes, which have a vertex-centered interpretation. +volumes, which can have either a vertex-centered or cell-centered +interpretation. The VDB implementation in Open VKL follows the following goals: @@ -1060,18 +1109,19 @@ The VDB implementation in Open VKL follows the following goals: VDB volumes are created by passing the type string `"vdb"` to `vklNewVolume`, and have the following parameters: -| Type | Name | Default | Description | -| :---------- | :------------------------------------ | :--------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| float\[\] | indexToObject | 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 | An array of 12 values of type `float` that define the transformation from index space to object space. In index space, the grid is an axis-aligned regular grid, and leaf voxels have size (1,1,1). The first 9 values are interpreted as a row-major linear transformation matrix. The last 3 values are the translation of the grid origin. | -| uint32\[\] | node.format | | For each input node, the data format. Currently supported are `VKL_FORMAT_TILE` for tiles, and `VKL_FORMAT_DENSE_ZYX` for nodes that are dense regular grids. | -| uint32\[\] | node.level | | For each input node, the level on which this node exists. Tiles may exist on levels \[1, `VKL_VDB_NUM_LEVELS-1`\], all other nodes may only exist on level `VKL_VDB_NUM_LEVELS-1`. | -| vec3i\[\] | node.origin | | For each input node, the node origin index. | -| VKLData\[\] | node.data | | For each input node, the attribute data. Single-attribute volumes may have one array provided per node, while multi-attribute volumes require an array per attribute for each node. Nodes with format `VKL_FORMAT_TILE` are expected to have single-entry arrays per attribute. Nodes with format `VKL_FORMAT_DENSE_ZYX` are expected to have arrays with `vklVdbLevelNumVoxels(level[i])` entries per attribute. `VKL_HALF` and `VKL_FLOAT` data is currently supported; all nodes for a given attribute must be the same data type. | -| uint32\[\] | node.temporalFormat | `VKL_TEMPORAL_FORMAT_CONSTANT` | The temporal format for this volume. Use `VKLTemporalFormat` for named constants. VDB volumes support `VKL_TEMPORAL_FORMAT_CONSTANT`, `VKL_TEMPORAL_FORMAT_STRUCTURED`, and `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | -| int\[\] | node.temporallyStructuredNumTimesteps | | For temporally structured variation, number of timesteps per voxel. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_STRUCTURED`. | -| VKLData\[\] | node.temporallyUnstructuredIndices | | For temporally unstructured variation, beginning per voxel. Supported data types for each node are `VKL_UINT` and `VKL_ULONG`. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | -| VKLData\[\] | node.temporallyUnstructuredTimes | | For temporally unstructured variation, time values corresponding to values in `node.data`. For each node, the data must be of type `VKL_FLOAT`. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | -| float\[\] | background | `VKL_BACKGROUND_UNDEFINED` | For each attribute, the value that is returned when sampling an undefined region outside the volume domain. | +| Type | Name | Default | Description | +| :----------------- | :------------------------------------ | :--------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| affine3f float\[\] | indexToObject | 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 | Defines the transformation from index space to object space. In index space, the grid is an axis-aligned regular grid, and leaf voxels have size (1,1,1). A `vkl_affine3f` can be provided; alternatively an array of 12 values of type `float` can be used, where the first 9 values are interpreted as a row-major linear transformation matrix, and the last 3 values are the translation of the grid origin. | +| uint32\[\] | node.format | | For each input node, the data format. Currently supported are `VKL_FORMAT_TILE` for tiles, and `VKL_FORMAT_DENSE_ZYX` for nodes that are dense regular grids. | +| uint32\[\] | node.level | | For each input node, the level on which this node exists. Tiles may exist on levels \[1, `VKL_VDB_NUM_LEVELS-1`\], all other nodes may only exist on level `VKL_VDB_NUM_LEVELS-1`. | +| vec3i\[\] | node.origin | | For each input node, the node origin index. | +| VKLData\[\] | node.data | | For each input node, the attribute data. Single-attribute volumes may have one array provided per node, while multi-attribute volumes require an array per attribute for each node. Nodes with format `VKL_FORMAT_TILE` are expected to have single-entry arrays per attribute. Nodes with format `VKL_FORMAT_DENSE_ZYX` are expected to have arrays with `vklVdbLevelNumVoxels(level[i])` entries per attribute. `VKL_HALF` and `VKL_FLOAT` data is currently supported; all nodes for a given attribute must be the same data type. | +| uint32\[\] | node.temporalFormat | `VKL_TEMPORAL_FORMAT_CONSTANT` | The temporal format for this volume. Use `VKLTemporalFormat` for named constants. VDB volumes support `VKL_TEMPORAL_FORMAT_CONSTANT`, `VKL_TEMPORAL_FORMAT_STRUCTURED`, and `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | +| int\[\] | node.temporallyStructuredNumTimesteps | | For temporally structured variation, number of timesteps per voxel. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_STRUCTURED`. | +| VKLData\[\] | node.temporallyUnstructuredIndices | | For temporally unstructured variation, beginning per voxel. Supported data types for each node are `VKL_UINT` and `VKL_ULONG`. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | +| VKLData\[\] | node.temporallyUnstructuredTimes | | For temporally unstructured variation, time values corresponding to values in `node.data`. For each node, the data must be of type `VKL_FLOAT`. Only valid if `temporalFormat` is `VKL_TEMPORAL_FORMAT_UNSTRUCTURED`. | +| float\[\] | background | `VKL_BACKGROUND_UNDEFINED` | For each attribute, the value that is returned when sampling an undefined region outside the volume domain. | +| box3i | indexClippingBounds | | Clips the volume to the specified index-space bounding box. This is useful for volumes with dimensions that are not even multiples of the leaf node dimensions, or .vdb files with restrictive active voxel bounding boxes. | Configuration parameters for VDB (`"vdb"`) volumes. @@ -1188,6 +1238,9 @@ each radial basis function phi, for each particle that overlaps it. Gradients are similarly computed, based on the summed analytical contributions of each contributing particle. +Particles with a radius less than or equal to zero are ignored. At least +one valid particle (radius greater than zero) must be provided. + The Open VKL implementation is similar to direct evaluation of samples in Reda et al.\[2\]. It uses an Embree-built BVH with a custom traversal, similar to the method in \[1\].