From 457ea4ee3a7c1fb8f533067e7dc79144a125aebb Mon Sep 17 00:00:00 2001 From: Jason Burmark Date: Wed, 10 Jul 2024 09:28:06 -0700 Subject: [PATCH 1/3] Remove volatile from RAJA atomics wrappers (#1325) The upcoming RAJA release will remove volatile from the atomics. --- .../runtimes/expressions/ascent_execution_policies.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/ascent/runtimes/expressions/ascent_execution_policies.hpp b/src/libs/ascent/runtimes/expressions/ascent_execution_policies.hpp index 36fa7f74b..9ebb64a2c 100644 --- a/src/libs/ascent/runtimes/expressions/ascent_execution_policies.hpp +++ b/src/libs/ascent/runtimes/expressions/ascent_execution_policies.hpp @@ -260,21 +260,21 @@ using ReduceMaxLoc = RAJA::ReduceMaxLoc; //---------------------------------------------------------------------------// template -ASCENT_EXEC T atomic_add(T volatile *acc, T value) +ASCENT_EXEC T atomic_add(T *acc, T value) { return RAJA::atomicAdd(ExecPolicy{}, acc, value); } //---------------------------------------------------------------------------// template -ASCENT_EXEC T atomic_min(T volatile *acc, T value) +ASCENT_EXEC T atomic_min(T *acc, T value) { return RAJA::atomicMin(ExecPolicy{}, acc, value); } //---------------------------------------------------------------------------// template -ASCENT_EXEC T atomic_max(T volatile *acc, T value) +ASCENT_EXEC T atomic_max(T *acc, T value) { return RAJA::atomicMax(ExecPolicy{}, acc, value); } From 86f0b679100c15eedd856e825505bd9d90d803ea Mon Sep 17 00:00:00 2001 From: Cyrus Harrison Date: Wed, 10 Jul 2024 12:33:35 -0700 Subject: [PATCH 2/3] bugfix for typo, provided by stephdempsey (#1327) --- src/libs/dray/utils/appstats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/dray/utils/appstats.cpp b/src/libs/dray/utils/appstats.cpp index a9c8826d0..c4683b386 100644 --- a/src/libs/dray/utils/appstats.cpp +++ b/src/libs/dray/utils/appstats.cpp @@ -261,7 +261,7 @@ StatStore::write_point_stats(const std::string &ofile_base) file.close(); m_point_stats.clear(); #else - (void) name; + (void) ofile_base; #endif } From a5f51b41e42c401e16b3003e3735dbe17e9ab2a9 Mon Sep 17 00:00:00 2001 From: Cyrus Harrison Date: Thu, 11 Jul 2024 15:00:47 -0700 Subject: [PATCH 3/3] bugfix for vtk-m ray culling issue (#1324) * add patch for ray tracing bug * add reproducer that demos vtk-m ray culling issue * link patches to vtk-m merge request * update containers to used patched vtk-m 2.1 --- azure-pipelines.yml | 10 +- ...4_07_02_vtkm-mr3246-raysubset_bugfix.patch | 43 ++++++++ scripts/build_ascent/build_ascent.sh | 3 +- ...4_07_02_vtkm-mr3246-raysubset_bugfix.patch | 43 ++++++++ .../uberenv_configs/packages/vtk-m/package.py | 4 + .../tout_render_3d_ray_z_cull_bug100.png | Bin 0 -> 403657 bytes src/tests/ascent/t_ascent_render_3d.cpp | 99 ++++++++++++++++++ 7 files changed, 196 insertions(+), 6 deletions(-) create mode 100644 scripts/build_ascent/2024_07_02_vtkm-mr3246-raysubset_bugfix.patch create mode 100644 scripts/uberenv_configs/packages/vtk-m/2024_07_02_vtkm-mr3246-raysubset_bugfix.patch create mode 100644 src/tests/_baseline_images/tout_render_3d_ray_z_cull_bug100.png diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 10501601f..69f5104c1 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,11 +22,11 @@ ######################## variables: - ubuntu_20_04_tag: alpinedav/ascent-devel:ubuntu-20.04-x86_64-tpls_2024-05-03-sha29a328 - ubuntu_22_04_tag: alpinedav/ascent-devel:ubuntu-22.04-x86_64-tpls_2024-05-09-shaa5bd0a - ubuntu_20_04_cuda_11_4_3_tag: alpinedav/ascent-devel:ubuntu-20.04-cuda-11.4.3-x86_64-tpls_2024-05-10-shaa5bd0a - ubuntu_20_04_cuda_12_1_1_tag: alpinedav/ascent-devel:ubuntu-20.04-cuda-12.1.1-x86_64-tpls_2024-05-10-shaa5bd0a - ubuntu_20_04_rocm_6_0_0_tag: alpinedav/ascent-devel:ubuntu-20.04-rocm-6.0.0--x86_64-build-ascent-tpls_2024-05-09-shaa5bd0a + ubuntu_20_04_tag: alpinedav/ascent-devel:ubuntu-20.04-x86_64-tpls_2024-07-09-sha3a1ef8 + ubuntu_22_04_tag: alpinedav/ascent-devel:ubuntu-22.04-x86_64-tpls_2024-07-10-sha3a1ef8 + ubuntu_20_04_cuda_11_4_3_tag: alpinedav/ascent-devel:ubuntu-20.04-cuda-11.4.3-x86_64-tpls_2024-07-09-sha3a1ef8 + ubuntu_20_04_cuda_12_1_1_tag: alpinedav/ascent-devel:ubuntu-20.04-cuda-12.1.1-x86_64-tpls_2024-07-09-sha3a1ef8 + ubuntu_20_04_rocm_6_0_0_tag: alpinedav/ascent-devel:ubuntu-20.04-rocm-6.0.0--x86_64-build-ascent-tpls_2024-07-10-sha3a1ef8 # only build merge target pr to develop diff --git a/scripts/build_ascent/2024_07_02_vtkm-mr3246-raysubset_bugfix.patch b/scripts/build_ascent/2024_07_02_vtkm-mr3246-raysubset_bugfix.patch new file mode 100644 index 000000000..db4f075cd --- /dev/null +++ b/scripts/build_ascent/2024_07_02_vtkm-mr3246-raysubset_bugfix.patch @@ -0,0 +1,43 @@ +From 763f13306b719bf6a213d00ead13fc93433e942e Mon Sep 17 00:00:00 2001 +From: Cyrus Harrison +Date: Tue, 2 Jul 2024 10:28:43 -0700 +Subject: [PATCH] fix bug with ray subsetting using wrong near and far planes + +--- + vtkm/rendering/raytracing/Camera.cxx | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/vtkm/rendering/raytracing/Camera.cxx b/vtkm/rendering/raytracing/Camera.cxx +index f2a39bef9..10febf39f 100644 +--- a/vtkm/rendering/raytracing/Camera.cxx ++++ b/vtkm/rendering/raytracing/Camera.cxx +@@ -830,6 +830,7 @@ void Camera::FindSubset(const vtkm::Bounds& bounds) + transformed[2] = (transformed[2] * 0.5f + 0.5f); + zmin = vtkm::Min(zmin, transformed[2]); + zmax = vtkm::Max(zmax, transformed[2]); ++ // skip if outside near and far clipping + if (transformed[2] < 0 || transformed[2] > 1) + { + continue; +@@ -894,15 +895,10 @@ VTKM_CONT void Camera::UpdateDimensions(Ray& rays, + this->CameraView.SetLookAt(this->GetLookAt()); + this->CameraView.SetPosition(this->GetPosition()); + this->CameraView.SetViewUp(this->GetUp()); +- // +- // Just create come clipping range, we ignore the zmax value in subsetting +- // +- vtkm::Float64 maxDim = vtkm::Max( +- boundingBox.X.Max - boundingBox.X.Min, +- vtkm::Max(boundingBox.Y.Max - boundingBox.Y.Min, boundingBox.Z.Max - boundingBox.Z.Min)); + +- maxDim *= 100; +- this->CameraView.SetClippingRange(.0001, maxDim); ++ // Note: ++ // Use clipping range provided, the subsetting does take into consideration ++ // the near and far clipping planes. + + //Update our ViewProjection matrix + this->ViewProjectionMat = +-- +2.39.3 (Apple Git-145) + diff --git a/scripts/build_ascent/build_ascent.sh b/scripts/build_ascent/build_ascent.sh index 39f65cdd5..bd330f9e2 100755 --- a/scripts/build_ascent/build_ascent.sh +++ b/scripts/build_ascent/build_ascent.sh @@ -171,7 +171,7 @@ set | grep build_ ################ # Zlib ################ -zlib_version=1.3 +zlib_version=1.3.1 zlib_src_dir=$(ospath ${root_dir}/zlib-${zlib_version}) zlib_build_dir=$(ospath ${root_dir}/build/zlib-${zlib_version}/) zlib_install_dir=$(ospath ${install_dir}/zlib-${zlib_version}/) @@ -364,6 +364,7 @@ if [ ! -d ${vtkm_src_dir} ]; then cd ${vtkm_src_dir} patch -p1 < ${script_dir}/2023_12_06_vtkm-mr3160-rocthrust-fix.patch patch -p1 < ${script_dir}/2024_05_03_vtkm-mr3215-ext-geom-fix.patch + patch -p1 < ${script_dir}/2024_07_02_vtkm-mr3246-raysubset_bugfix.patch cd ${root_dir} fi diff --git a/scripts/uberenv_configs/packages/vtk-m/2024_07_02_vtkm-mr3246-raysubset_bugfix.patch b/scripts/uberenv_configs/packages/vtk-m/2024_07_02_vtkm-mr3246-raysubset_bugfix.patch new file mode 100644 index 000000000..db4f075cd --- /dev/null +++ b/scripts/uberenv_configs/packages/vtk-m/2024_07_02_vtkm-mr3246-raysubset_bugfix.patch @@ -0,0 +1,43 @@ +From 763f13306b719bf6a213d00ead13fc93433e942e Mon Sep 17 00:00:00 2001 +From: Cyrus Harrison +Date: Tue, 2 Jul 2024 10:28:43 -0700 +Subject: [PATCH] fix bug with ray subsetting using wrong near and far planes + +--- + vtkm/rendering/raytracing/Camera.cxx | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/vtkm/rendering/raytracing/Camera.cxx b/vtkm/rendering/raytracing/Camera.cxx +index f2a39bef9..10febf39f 100644 +--- a/vtkm/rendering/raytracing/Camera.cxx ++++ b/vtkm/rendering/raytracing/Camera.cxx +@@ -830,6 +830,7 @@ void Camera::FindSubset(const vtkm::Bounds& bounds) + transformed[2] = (transformed[2] * 0.5f + 0.5f); + zmin = vtkm::Min(zmin, transformed[2]); + zmax = vtkm::Max(zmax, transformed[2]); ++ // skip if outside near and far clipping + if (transformed[2] < 0 || transformed[2] > 1) + { + continue; +@@ -894,15 +895,10 @@ VTKM_CONT void Camera::UpdateDimensions(Ray& rays, + this->CameraView.SetLookAt(this->GetLookAt()); + this->CameraView.SetPosition(this->GetPosition()); + this->CameraView.SetViewUp(this->GetUp()); +- // +- // Just create come clipping range, we ignore the zmax value in subsetting +- // +- vtkm::Float64 maxDim = vtkm::Max( +- boundingBox.X.Max - boundingBox.X.Min, +- vtkm::Max(boundingBox.Y.Max - boundingBox.Y.Min, boundingBox.Z.Max - boundingBox.Z.Min)); + +- maxDim *= 100; +- this->CameraView.SetClippingRange(.0001, maxDim); ++ // Note: ++ // Use clipping range provided, the subsetting does take into consideration ++ // the near and far clipping planes. + + //Update our ViewProjection matrix + this->ViewProjectionMat = +-- +2.39.3 (Apple Git-145) + diff --git a/scripts/uberenv_configs/packages/vtk-m/package.py b/scripts/uberenv_configs/packages/vtk-m/package.py index be1039c20..4cd15546b 100644 --- a/scripts/uberenv_configs/packages/vtk-m/package.py +++ b/scripts/uberenv_configs/packages/vtk-m/package.py @@ -164,6 +164,10 @@ class VtkM(CMakePackage, CudaPackage, ROCmPackage): # https://gitlab.kitware.com/vtk/vtk-m/-/merge_requests/3160 patch("mr3160-rocthrust-fix.patch", when="@2.1:") + # VTK-M future PR + # + patch("2024_07_02_vtkm-mr3246-raysubset_bugfix.patch", when="@2.1:") + def cmake_args(self): spec = self.spec options = [] diff --git a/src/tests/_baseline_images/tout_render_3d_ray_z_cull_bug100.png b/src/tests/_baseline_images/tout_render_3d_ray_z_cull_bug100.png new file mode 100644 index 0000000000000000000000000000000000000000..e5f7a281bb0ceb3fc70393d388a1fa56a73b09c2 GIT binary patch literal 403657 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 z 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