//============================================================================ // 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. // // Copyright 2014 Sandia Corporation. // Copyright 2014 UT-Battelle, LLC. // Copyright 2014 Los Alamos National Security. // // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, // the U.S. Government retains certain rights in this software. // // Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National // Laboratory (LANL), the U.S. Government retains certain rights in // this software. //============================================================================ #ifndef vtk_m_cont_cuda_internal_MakeThrustIterator_h #define vtk_m_cont_cuda_internal_MakeThrustIterator_h #include #include #include #include // Disable warnings we check vtkm for but Thrust does not. #if defined(__GNUC__) || defined(____clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wconversion" #endif // gcc || clang #include #include #include #include #include #if defined(__GNUC__) || defined(____clang__) #pragma GCC diagnostic pop #endif // gcc || clang //needed forward declares namespace vtkm { namespace exec { namespace internal { template class ArrayPortalExecZip; } } } namespace vtkm { namespace cont { namespace cuda { namespace internal { namespace detail { // Tags to specify what type of thrust iterator to use. struct ThrustIteratorTransformTag { }; struct ThrustIteratorZipTag { }; struct ThrustIteratorDevicePtrTag { }; // Traits to help classify what thrust iterators will be used. template struct ThrustIteratorTag { typedef ThrustIteratorTransformTag Type; }; template struct ThrustIteratorTag { typedef ThrustIteratorDevicePtrTag Type; }; template struct ThrustIteratorTag { typedef ThrustIteratorDevicePtrTag Type; }; template struct ThrustIteratorTag< vtkm::exec::internal::ArrayPortalExecZip< T, U, V >, T > { //this is a real special case. ExecZip and PortalValue don't combine //well together, when used with DeviceAlgorithm that has a custom operator //the custom operator is actually passed the PortalValue instead of //the real values, and by that point we can't fix anything since we //don't know what the original operator is typedef ThrustIteratorZipTag Type; }; template struct ThrustStripPointer; template struct ThrustStripPointer { typedef T Type; }; template struct ThrustStripPointer { typedef const T Type; }; template struct PortalValue { typedef typename PortalType::ValueType ValueType; VTKM_EXEC_EXPORT PortalValue() : Portal(), Index(0) { } VTKM_EXEC_EXPORT PortalValue(const PortalType &portal, vtkm::Id index) : Portal(portal), Index(index) { } VTKM_EXEC_EXPORT PortalValue(const PortalValue &other) : Portal(other.Portal), Index(other.Index) { } VTKM_EXEC_EXPORT ValueType operator=(ValueType value) { this->Portal.Set(this->Index, value); return value; } VTKM_EXEC_EXPORT operator ValueType(void) const { return this->Portal.Get(this->Index); } const PortalType Portal; const vtkm::Id Index; }; template class LookupFunctor : public ::thrust::unary_function > { public: VTKM_EXEC_EXPORT LookupFunctor() : Portal() { } VTKM_EXEC_EXPORT LookupFunctor(PortalType portal) : Portal(portal) { } VTKM_EXEC_EXPORT PortalValue operator()(vtkm::Id index) { return PortalValue(this->Portal, index); } private: PortalType Portal; }; template struct IteratorChooser; template struct IteratorChooser { typedef ::thrust::transform_iterator< LookupFunctor, ::thrust::counting_iterator > Type; }; template struct IteratorChooser { //this is a real special case. ExecZip and PortalValue don't combine //well together, when used with DeviceAlgorithm that has a custom operator //the custom operator is actually passed the PortalValue instead of //the real values, and by that point we can't fix anything since we //don't know what the original operator is. //So to fix this issue we wrap the original array portals into a thrust //zip iterator and let handle everything typedef typename PortalType::PortalTypeFirst PortalTypeFirst; typedef typename IteratorTraits::IteratorType FirstIterType; typedef typename PortalType::PortalTypeSecond PortalTypeSecond; typedef typename IteratorTraits::IteratorType SecondIterType; //Now that we have deduced the concrete types of the first and second //array portals of the zip we can construct a zip iterator for those typedef ::thrust::tuple IteratorTuple; typedef ::thrust::zip_iterator Type; }; template struct IteratorChooser { typedef ::thrust::cuda::pointer< typename detail::ThrustStripPointer< typename PortalType::IteratorType>::Type> Type; }; template struct IteratorTraits { typedef typename detail::ThrustIteratorTag< PortalType, typename PortalType::IteratorType>::Type Tag; typedef typename IteratorChooser::Type IteratorType; }; template VTKM_CONT_EXPORT static ::thrust::cuda::pointer MakeDevicePtr(T *iter) { return::thrust::cuda::pointer(iter); } template VTKM_CONT_EXPORT static ::thrust::cuda::pointer MakeDevicePtr(const T *iter) { return ::thrust::cuda::pointer(iter); } template VTKM_CONT_EXPORT static ::thrust::zip_iterator MakeZipIterator(const T t, const U u) { //todo deduce from T and U the iterator types this is what needs finished return ::thrust::make_zip_iterator( ::thrust::make_tuple( IteratorBegin(t), IteratorBegin(u) ) ); } template VTKM_CONT_EXPORT static typename IteratorTraits::IteratorType MakeIteratorBegin(PortalType portal, detail::ThrustIteratorTransformTag) { return ::thrust::make_transform_iterator( ::thrust::make_counting_iterator(vtkm::Id(0)), LookupFunctor(portal)); } template VTKM_CONT_EXPORT static typename IteratorTraits::IteratorType MakeIteratorBegin(PortalType portal, detail::ThrustIteratorZipTag) { return MakeZipIterator(portal.GetFirstPortal(), portal.GetSecondPortal() ); } template VTKM_CONT_EXPORT static typename IteratorTraits::IteratorType MakeIteratorBegin(PortalType portal, detail::ThrustIteratorDevicePtrTag) { return MakeDevicePtr(portal.GetIteratorBegin()); } } // namespace detail template VTKM_CONT_EXPORT typename detail::IteratorTraits::IteratorType IteratorBegin(PortalType portal) { typedef typename detail::IteratorTraits::Tag IteratorTag; return detail::MakeIteratorBegin(portal, IteratorTag()); } template VTKM_CONT_EXPORT typename detail::IteratorTraits::IteratorType IteratorEnd(PortalType portal) { return IteratorBegin(portal) + portal.GetNumberOfValues(); } } } } } //namespace vtkm::cont::cuda::internal namespace thrust { template< typename PortalType > struct less< vtkm::cont::cuda::internal::detail::PortalValue< PortalType > > : public binary_function< vtkm::cont::cuda::internal::detail::PortalValue< PortalType >, vtkm::cont::cuda::internal::detail::PortalValue< PortalType >, bool> { typedef vtkm::cont::cuda::internal::detail::PortalValue< PortalType > T; typedef typename vtkm::cont::cuda::internal::detail::PortalValue< PortalType >::ValueType ValueType; /*! Function call operator. The return value is lhs < rhs. */ __host__ __device__ bool operator()(const T &lhs, const T &rhs) const {return (ValueType)lhs < (ValueType)rhs;} /*! Function call operator. The return value is lhs < rhs. specially designed to work with vtkm portal values, which can be compared to their underline type */ __host__ __device__ bool operator()(const T &lhs, const ValueType &rhs) const {return (ValueType)lhs < rhs;} }; // end less } #endif