From 445e4d8186a2fbfa403d5a6d4df165af421492cb Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Fri, 27 Sep 2019 16:40:53 -0400 Subject: [PATCH] vtkm::cont::Invoker supports both Masks and Scatter Fixes #420 --- vtkm/cont/Invoker.h | 56 ++++++++++++++++++------- vtkm/worklet/MaskIndices.h | 3 +- vtkm/worklet/MaskNone.h | 3 +- vtkm/worklet/MaskSelect.h | 5 ++- vtkm/worklet/OrientCellNormals.h | 58 ++++++++++++++------------ vtkm/worklet/internal/CMakeLists.txt | 2 + vtkm/worklet/internal/DecayHelpers.h | 30 +++++++++++++ vtkm/worklet/internal/DispatcherBase.h | 15 ++----- vtkm/worklet/internal/MaskBase.h | 37 ++++++++++++++++ vtkm/worklet/internal/ScatterBase.h | 5 ++- 10 files changed, 156 insertions(+), 58 deletions(-) create mode 100644 vtkm/worklet/internal/DecayHelpers.h create mode 100644 vtkm/worklet/internal/MaskBase.h diff --git a/vtkm/cont/Invoker.h b/vtkm/cont/Invoker.h index dfc2dfdb3..5117814a0 100644 --- a/vtkm/cont/Invoker.h +++ b/vtkm/cont/Invoker.h @@ -22,6 +22,13 @@ namespace vtkm namespace cont { +namespace detail +{ +template +using scatter_or_mask = std::integral_constant::value || + vtkm::worklet::internal::is_scatter::value>; +} /// \brief Allows launching any worklet without a dispatcher. /// @@ -53,40 +60,59 @@ struct Invoker } /// Launch the worklet that is provided as the first parameter. - /// Optional second parameter is the scatter type associated with the worklet. + /// Optional second parameter is either the scatter or mask type associated with the worklet. /// Any additional parameters are the ControlSignature arguments for the worklet. /// - template < - typename Worklet, - typename T, - typename... Args, - typename std::enable_if>::value, - int>::type* = nullptr> - inline void operator()(Worklet&& worklet, T&& scatter, Args&&... args) const + template ::value, int>::type* = nullptr> + inline void operator()(Worklet&& worklet, T&& scatterOrMask, Args&&... args) const { - using WorkletType = worklet::internal::detail::remove_cvref; + using WorkletType = worklet::internal::remove_cvref; using DispatcherType = typename WorkletType::template Dispatcher; - DispatcherType dispatcher(worklet, scatter); + DispatcherType dispatcher(worklet, scatterOrMask); dispatcher.SetDevice(this->DeviceId); dispatcher.Invoke(std::forward(args)...); } /// Launch the worklet that is provided as the first parameter. - /// Optional second parameter is the scatter type associated with the worklet. + /// Optional second parameter is either the scatter or mask type associated with the worklet. + /// Optional third parameter is either the scatter or mask type associated with the worklet. /// Any additional parameters are the ControlSignature arguments for the worklet. /// template < typename Worklet, typename T, + typename U, typename... Args, - typename std::enable_if>::value, + typename std::enable_if::value && detail::scatter_or_mask::value, int>::type* = nullptr> + inline void operator()(Worklet&& worklet, + T&& scatterOrMaskA, + U&& scatterOrMaskB, + Args&&... args) const + { + using WorkletType = worklet::internal::remove_cvref; + using DispatcherType = typename WorkletType::template Dispatcher; + + DispatcherType dispatcher(worklet, scatterOrMaskA, scatterOrMaskB); + dispatcher.SetDevice(this->DeviceId); + dispatcher.Invoke(std::forward(args)...); + } + + /// Launch the worklet that is provided as the first parameter. + /// Optional second parameter is either the scatter or mask type associated with the worklet. + /// Any additional parameters are the ControlSignature arguments for the worklet. + /// + template ::value, int>::type* = nullptr> inline void operator()(Worklet&& worklet, T&& t, Args&&... args) const { - using WorkletType = worklet::internal::detail::remove_cvref; + using WorkletType = worklet::internal::remove_cvref; using DispatcherType = typename WorkletType::template Dispatcher; DispatcherType dispatcher(worklet); diff --git a/vtkm/worklet/MaskIndices.h b/vtkm/worklet/MaskIndices.h index 99088e4e5..cd4b566e1 100644 --- a/vtkm/worklet/MaskIndices.h +++ b/vtkm/worklet/MaskIndices.h @@ -11,6 +11,7 @@ #define vtk_m_worklet_MaskIndices_h #include +#include namespace vtkm { @@ -26,7 +27,7 @@ namespace worklet /// It is OK to give indices that are out of order, but any index must be provided at most one /// time. It is an error to have the same index listed twice. /// -class MaskIndices +class MaskIndices : public internal::MaskBase { public: using ThreadToOutputMapType = vtkm::cont::ArrayHandle; diff --git a/vtkm/worklet/MaskNone.h b/vtkm/worklet/MaskNone.h index 2dfcfbaf5..9a864b4c1 100644 --- a/vtkm/worklet/MaskNone.h +++ b/vtkm/worklet/MaskNone.h @@ -11,6 +11,7 @@ #define vtk_m_worklet_MaskNone_h #include +#include namespace vtkm { @@ -23,7 +24,7 @@ namespace worklet /// domain. This is the default mask object so that the worklet is run for every possible /// output element. /// -struct MaskNone +struct MaskNone : public internal::MaskBase { template VTKM_CONT RangeType GetThreadRange(RangeType outputRange) const diff --git a/vtkm/worklet/MaskSelect.h b/vtkm/worklet/MaskSelect.h index 284ee930a..51ffd3a50 100644 --- a/vtkm/worklet/MaskSelect.h +++ b/vtkm/worklet/MaskSelect.h @@ -10,6 +10,7 @@ #ifndef vtk_m_worklet_MaskSelect_h #define vtk_m_worklet_MaskSelect_h +#include #include #include @@ -21,7 +22,7 @@ namespace worklet /// \brief Mask using arrays to select specific elements to suppress. /// -/// \c MaskSelect is a worklet mask object that is used to select elementsin the output of a +/// \c MaskSelect is a worklet mask object that is used to select elements in the output of a /// worklet to suppress the invocation. That is, the worklet will only be invoked for elements in /// the output that are not masked out by the given array. /// @@ -29,7 +30,7 @@ namespace worklet /// that should be masked and a 1 for any output that should be generated. It is an error to have /// any value that is not a 0 or 1. This method is slower than specifying an index array. /// -class VTKM_WORKLET_EXPORT MaskSelect +class VTKM_WORKLET_EXPORT MaskSelect : public internal::MaskBase { struct MaskTypes : vtkm::ListTagBase #include #include +#include #include -#include -#include #include #include #include @@ -336,12 +335,6 @@ public: { using RangeType = vtkm::cont::ArrayHandle; - using MarkSourcePoints = vtkm::worklet::DispatcherMapField; - using ProcessSourceCells = vtkm::worklet::DispatcherMapTopology; - using MarkActivePoints = vtkm::worklet::DispatcherMapTopology; - using MarkActiveCells = vtkm::worklet::DispatcherMapTopology; - using ProcessCellNormals = vtkm::worklet::DispatcherMapField; - const vtkm::Id numPoints = coords.GetNumberOfValues(); const vtkm::Id numCells = cells.GetNumberOfCells(); @@ -367,6 +360,7 @@ public: vtkm::cont::Algorithm::Fill(visitedCellBits, false, numCells); auto visitedCells = vtkm::cont::make_ArrayHandleBitField(visitedCellBits); + vtkm::cont::Invoker invoke; vtkm::cont::ArrayHandle mask; // Allocated as needed // For each cell, store a reference alignment cell. @@ -381,10 +375,7 @@ public: // 2) Locate points on a boundary, since their normal alignment direction // is known. - { - MarkSourcePoints dispatcher; - dispatcher.Invoke(coords, ranges, activePoints); - } + invoke(WorkletMarkSourcePoints{}, coords, ranges, activePoints); // 3) For each source point, align the normals of the adjacent cells. { @@ -392,15 +383,16 @@ public: (void)numActive; VTKM_LOG_S(vtkm::cont::LogLevel::Perf, "ProcessSourceCells from " << numActive << " source points."); - ProcessSourceCells dispatcher{ vtkm::worklet::MaskIndices{ mask } }; - dispatcher.Invoke(cells, - coords, - ranges, - cellNormals, - activeCellBits, - visitedCellBits, - activePoints, - visitedPoints); + invoke(WorkletProcessSourceCells{}, + vtkm::worklet::MaskIndices{ mask }, + cells, + coords, + ranges, + cellNormals, + activeCellBits, + visitedCellBits, + activePoints, + visitedPoints); } for (size_t iter = 1;; ++iter) @@ -411,8 +403,12 @@ public: (void)numActive; VTKM_LOG_S(vtkm::cont::LogLevel::Perf, "MarkActivePoints from " << numActive << " active cells."); - MarkActivePoints dispatcher{ vtkm::worklet::MaskIndices{ mask } }; - dispatcher.Invoke(cells, activePointBits, visitedPointBits, activeCells); + invoke(WorkletMarkActivePoints{}, + vtkm::worklet::MaskIndices{ mask }, + cells, + activePointBits, + visitedPointBits, + activeCells); } // 5) Mark unvisited cells adjacent to active points @@ -421,8 +417,13 @@ public: (void)numActive; VTKM_LOG_S(vtkm::cont::LogLevel::Perf, "MarkActiveCells from " << numActive << " active points."); - MarkActiveCells dispatcher{ vtkm::worklet::MaskIndices{ mask } }; - dispatcher.Invoke(cells, refCells, activeCellBits, visitedCellBits, activePoints); + invoke(WorkletMarkActiveCells{}, + vtkm::worklet::MaskIndices{ mask }, + cells, + refCells, + activeCellBits, + visitedCellBits, + activePoints); } vtkm::Id numActiveCells = vtkm::cont::Algorithm::BitFieldToUnorderedSet(activeCellBits, mask); @@ -438,8 +439,11 @@ public: // 5) Correct normals for active cells. { - ProcessCellNormals dispatcher{ vtkm::worklet::MaskIndices{ mask } }; - dispatcher.Invoke(refCells, cellNormals, visitedCells); + invoke(WorkletProcessCellNormals{}, + vtkm::worklet::MaskIndices{ mask }, + refCells, + cellNormals, + visitedCells); } } } diff --git a/vtkm/worklet/internal/CMakeLists.txt b/vtkm/worklet/internal/CMakeLists.txt index 4a21b0b00..d9f8e7bd0 100644 --- a/vtkm/worklet/internal/CMakeLists.txt +++ b/vtkm/worklet/internal/CMakeLists.txt @@ -9,7 +9,9 @@ ##============================================================================ set(headers + DecayHelpers.h DispatcherBase.h + MaskBase.h ScatterBase.h TriangulateTables.h WorkletBase.h diff --git a/vtkm/worklet/internal/DecayHelpers.h b/vtkm/worklet/internal/DecayHelpers.h new file mode 100644 index 000000000..7c429deaa --- /dev/null +++ b/vtkm/worklet/internal/DecayHelpers.h @@ -0,0 +1,30 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//============================================================================ +#ifndef vtk_m_worklet_internal_DecayHelpers_h +#define vtk_m_worklet_internal_DecayHelpers_h + +#include + +namespace vtkm +{ +namespace worklet +{ +namespace internal +{ + +template +using remove_pointer_and_decay = typename std::remove_pointer::type>::type; + +template +using remove_cvref = typename std::remove_cv::type>::type; +} +} +} +#endif diff --git a/vtkm/worklet/internal/DispatcherBase.h b/vtkm/worklet/internal/DispatcherBase.h index f6a8c4008..11f5eb179 100644 --- a/vtkm/worklet/internal/DispatcherBase.h +++ b/vtkm/worklet/internal/DispatcherBase.h @@ -29,6 +29,7 @@ #include +#include #include #include @@ -168,12 +169,6 @@ struct ReportValueOnError : std::true_type { }; -template -using remove_pointer_and_decay = typename std::remove_pointer::type>::type; - -template -using remove_cvref = typename std::remove_cv::type>::type; - // Is designed as a brigand fold operation. template struct DetermineIfHasDynamicParameter @@ -510,8 +505,7 @@ private: template VTKM_CONT void StartInvoke(Args&&... args) const { - using ParameterInterface = - vtkm::internal::FunctionInterface...)>; + using ParameterInterface = vtkm::internal::FunctionInterface...)>; VTKM_STATIC_ASSERT_MSG(ParameterInterface::ARITY == NUM_INVOKE_PARAMS, "Dispatcher Invoke called with wrong number of arguments."); @@ -556,8 +550,7 @@ private: template VTKM_CONT void StartInvokeDynamic(std::false_type, Args&&... args) const { - using ParameterInterface = - vtkm::internal::FunctionInterface...)>; + using ParameterInterface = vtkm::internal::FunctionInterface...)>; //Nothing requires a conversion from dynamic to static types, so //next we need to verify that each argument's type is correct. If not @@ -578,7 +571,7 @@ private: static_assert(isAllValid::value == expectedLen::value, "All arguments failed the TypeCheck pass"); - auto fi = vtkm::internal::make_FunctionInterface...>(args...); + auto fi = vtkm::internal::make_FunctionInterface...>(args...); auto ivc = vtkm::internal::Invocation +#include + +namespace vtkm +{ +namespace worklet +{ +namespace internal +{ + +/// Base class for all mask classes. +/// +/// This allows VTK-m to determine when a parameter +/// is a mask type instead of a worklet parameter. +/// +struct VTKM_ALWAYS_EXPORT MaskBase +{ +}; + +template +using is_mask = std::is_base_of>; +} +} +} +#endif diff --git a/vtkm/worklet/internal/ScatterBase.h b/vtkm/worklet/internal/ScatterBase.h index 7a89d42fb..39aa3ee71 100644 --- a/vtkm/worklet/internal/ScatterBase.h +++ b/vtkm/worklet/internal/ScatterBase.h @@ -11,6 +11,7 @@ #define vtk_m_worklet_internal_ScatterBase_h #include +#include namespace vtkm { @@ -18,7 +19,6 @@ namespace worklet { namespace internal { - /// Base class for all scatter classes. /// /// This allows VTK-m to determine when a parameter @@ -27,6 +27,9 @@ namespace internal struct VTKM_ALWAYS_EXPORT ScatterBase { }; + +template +using is_scatter = std::is_base_of>; } } }