mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-08 03:18:58 +00:00
Add ArrayCopy fast paths
There are some common uses of `ArrayCopy` that don't use basic arrays. Rather than move away from `ArrayCopy` for these use cases, compile a special fast path for these cases. This required some restructuring of the code to get the template resolution to work correctly.
This commit is contained in:
parent
00609b0af2
commit
f3c82bfea7
@ -10,8 +10,15 @@
|
||||
#ifndef vtk_m_cont_ArrayCopy_h
|
||||
#define vtk_m_cont_ArrayCopy_h
|
||||
|
||||
#include <vtkm/cont/ArrayHandleConcatenate.h>
|
||||
#include <vtkm/cont/ArrayHandleConstant.h>
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/ArrayHandlePermutation.h>
|
||||
#include <vtkm/cont/ArrayHandleView.h>
|
||||
#include <vtkm/cont/UnknownArrayHandle.h>
|
||||
|
||||
#include <vtkm/cont/internal/MapArrayPermutation.h>
|
||||
|
||||
#include <vtkm/StaticAssert.h>
|
||||
#include <vtkm/VecTraits.h>
|
||||
|
||||
@ -38,6 +45,70 @@ inline void ArrayCopyValueTypeCheck()
|
||||
"see the offending type.");
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
struct ArrayCopyConcreteSrc;
|
||||
|
||||
template <typename SrcIsArrayHandle>
|
||||
inline void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source,
|
||||
vtkm::cont::UnknownArrayHandle& destination,
|
||||
SrcIsArrayHandle,
|
||||
std::false_type)
|
||||
{
|
||||
destination.DeepCopyFrom(source);
|
||||
}
|
||||
template <typename SrcIsArrayHandle>
|
||||
inline void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source,
|
||||
const vtkm::cont::UnknownArrayHandle& destination,
|
||||
SrcIsArrayHandle,
|
||||
std::false_type)
|
||||
{
|
||||
destination.DeepCopyFrom(source);
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source,
|
||||
vtkm::cont::ArrayHandle<T, S>& destination,
|
||||
std::false_type,
|
||||
std::true_type)
|
||||
{
|
||||
detail::ArrayCopyValueTypeCheck<T>();
|
||||
|
||||
using DestType = vtkm::cont::ArrayHandle<T, S>;
|
||||
if (source.CanConvert<DestType>())
|
||||
{
|
||||
destination.DeepCopyFrom(source.AsArrayHandle<DestType>());
|
||||
}
|
||||
else
|
||||
{
|
||||
vtkm::cont::UnknownArrayHandle destWrapper(destination);
|
||||
vtkm::cont::detail::ArrayCopyImpl(source, destWrapper, std::false_type{}, std::false_type{});
|
||||
// Destination array should not change, but just in case.
|
||||
destWrapper.AsArrayHandle(destination);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TS, typename SS, typename TD, typename SD>
|
||||
void ArrayCopyImpl(const vtkm::cont::ArrayHandle<TS, SS>& source,
|
||||
vtkm::cont::ArrayHandle<TD, SD>& destination,
|
||||
std::true_type,
|
||||
std::true_type)
|
||||
{
|
||||
ArrayCopyValueTypeCheck<TS>();
|
||||
ArrayCopyValueTypeCheck<TD>();
|
||||
|
||||
detail::ArrayCopyConcreteSrc<SS>{}(source, destination);
|
||||
}
|
||||
|
||||
// Special case of copying data when type is the same.
|
||||
template <typename T, typename S>
|
||||
void ArrayCopyImpl(const vtkm::cont::ArrayHandle<T, S>& source,
|
||||
vtkm::cont::ArrayHandle<T, S>& destination,
|
||||
std::true_type,
|
||||
std::true_type)
|
||||
{
|
||||
destination.DeepCopyFrom(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// \brief Does a deep copy from one array to another array.
|
||||
@ -64,51 +135,23 @@ inline void ArrayCopyValueTypeCheck()
|
||||
///
|
||||
/// @{
|
||||
///
|
||||
inline void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
|
||||
vtkm::cont::UnknownArrayHandle& destination)
|
||||
template <typename SourceArrayType, typename DestArrayType>
|
||||
inline void ArrayCopy(const SourceArrayType& source, DestArrayType& destination)
|
||||
{
|
||||
destination.DeepCopyFrom(source);
|
||||
}
|
||||
inline void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
|
||||
const vtkm::cont::UnknownArrayHandle& destination)
|
||||
{
|
||||
destination.DeepCopyFrom(source);
|
||||
detail::ArrayCopyImpl(source,
|
||||
destination,
|
||||
typename internal::ArrayHandleCheck<SourceArrayType>::type{},
|
||||
typename internal::ArrayHandleCheck<DestArrayType>::type{});
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
|
||||
vtkm::cont::ArrayHandle<T, S>& destination)
|
||||
// Special case where we allow a const UnknownArrayHandle as output.
|
||||
template <typename SourceArrayType>
|
||||
inline void ArrayCopy(const SourceArrayType& source, vtkm::cont::UnknownArrayHandle& destination)
|
||||
{
|
||||
detail::ArrayCopyValueTypeCheck<T>();
|
||||
|
||||
using DestType = vtkm::cont::ArrayHandle<T, S>;
|
||||
if (source.CanConvert<DestType>())
|
||||
{
|
||||
destination.DeepCopyFrom(source.AsArrayHandle<DestType>());
|
||||
}
|
||||
else
|
||||
{
|
||||
vtkm::cont::UnknownArrayHandle destWrapper(destination);
|
||||
vtkm::cont::ArrayCopy(source, destWrapper);
|
||||
// Destination array should not change, but just in case.
|
||||
destWrapper.AsArrayHandle(destination);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S, typename DestArray>
|
||||
void ArrayCopy(const vtkm::cont::ArrayHandle<T, S>& source, DestArray& destination)
|
||||
{
|
||||
detail::ArrayCopyValueTypeCheck<T>();
|
||||
|
||||
vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle{ source }, destination);
|
||||
}
|
||||
|
||||
// Special case of copying data when type is the same.
|
||||
template <typename T, typename S>
|
||||
void ArrayCopy(const vtkm::cont::ArrayHandle<T, S>& source,
|
||||
vtkm::cont::ArrayHandle<T, S>& destination)
|
||||
{
|
||||
destination.DeepCopyFrom(source);
|
||||
detail::ArrayCopyImpl(source,
|
||||
destination,
|
||||
typename internal::ArrayHandleCheck<SourceArrayType>::type{},
|
||||
std::false_type{});
|
||||
}
|
||||
|
||||
// Invalid const ArrayHandle in destination, which is not allowed because it will
|
||||
@ -150,6 +193,111 @@ VTKM_CONT void ArrayCopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle s
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename S>
|
||||
struct ArrayCopyConcreteSrc
|
||||
{
|
||||
template <typename T, typename DestArray>
|
||||
void operator()(const vtkm::cont::ArrayHandle<T, S>& source, DestArray& destination) const
|
||||
{
|
||||
using ArrayType = vtkm::cont::ArrayHandle<T, S>;
|
||||
this->DoIt(
|
||||
source, destination, vtkm::cont::internal::ArrayExtractComponentIsInefficient<ArrayType>{});
|
||||
}
|
||||
|
||||
template <typename T, typename DestArray>
|
||||
void DoIt(const vtkm::cont::ArrayHandle<T, S>& source,
|
||||
DestArray& destination,
|
||||
std::false_type vtkmNotUsed(isInefficient)) const
|
||||
{
|
||||
vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle{ source }, destination);
|
||||
}
|
||||
|
||||
template <typename T, typename DestArray>
|
||||
void DoIt(const vtkm::cont::ArrayHandle<T, S>& source,
|
||||
DestArray& destination,
|
||||
std::true_type vtkmNotUsed(isInefficient)) const
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
|
||||
"Attempting to copy from an array of type " +
|
||||
vtkm::cont::TypeToString<vtkm::cont::ArrayHandle<T, S>>() +
|
||||
" with ArrayCopy is inefficient. It is highly recommended you use another method "
|
||||
"such as vtkm::cont::ArrayCopyDevice.");
|
||||
// Still call the precompiled `ArrayCopy`. You will get another warning after this,
|
||||
// but it will still technically work, albiet slowly.
|
||||
vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle{ source }, destination);
|
||||
}
|
||||
};
|
||||
|
||||
// Special case for constant arrays to be efficient.
|
||||
template <>
|
||||
struct ArrayCopyConcreteSrc<vtkm::cont::StorageTagConstant>
|
||||
{
|
||||
template <typename T1, typename T2, typename S2>
|
||||
void operator()(const vtkm::cont::ArrayHandle<T1, vtkm::cont::StorageTagConstant>& source_,
|
||||
vtkm::cont::ArrayHandle<T2, S2>& destination) const
|
||||
{
|
||||
vtkm::cont::ArrayHandleConstant<T1> source = source_;
|
||||
destination.AllocateAndFill(source.GetNumberOfValues(), static_cast<T2>(source.GetValue()));
|
||||
}
|
||||
};
|
||||
|
||||
// Special case for ArrayHandleIndex to be efficient.
|
||||
template <>
|
||||
struct ArrayCopyConcreteSrc<vtkm::cont::StorageTagIndex>
|
||||
{
|
||||
template <typename T, typename S>
|
||||
void operator()(const vtkm::cont::ArrayHandleIndex& source,
|
||||
vtkm::cont::ArrayHandle<T, S>& destination) const
|
||||
{
|
||||
// Skip warning about inefficient copy because there is a special case in ArrayCopyUnknown.cxx
|
||||
// to copy ArrayHandleIndex efficiently.
|
||||
vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle{ source }, destination);
|
||||
}
|
||||
};
|
||||
|
||||
// Special case for ArrayHandleConcatenate to be efficient
|
||||
template <typename ST1, typename ST2>
|
||||
struct ArrayCopyConcreteSrc<vtkm::cont::StorageTagConcatenate<ST1, ST2>>
|
||||
{
|
||||
template <typename SourceArrayType, typename DestArrayType>
|
||||
void operator()(const SourceArrayType& source, DestArrayType& destination) const
|
||||
{
|
||||
auto source1 = source.GetStorage().GetArray1(source.GetBuffers());
|
||||
auto source2 = source.GetStorage().GetArray2(source.GetBuffers());
|
||||
|
||||
// Need to preallocate because view decorator will not be able to resize.
|
||||
destination.Allocate(source.GetNumberOfValues());
|
||||
auto dest1 = vtkm::cont::make_ArrayHandleView(destination, 0, source1.GetNumberOfValues());
|
||||
auto dest2 = vtkm::cont::make_ArrayHandleView(
|
||||
destination, source1.GetNumberOfValues(), source2.GetNumberOfValues());
|
||||
|
||||
vtkm::cont::ArrayCopy(source1, dest1);
|
||||
vtkm::cont::ArrayCopy(source2, dest2);
|
||||
}
|
||||
};
|
||||
|
||||
// Special case for ArrayHandlePermutation to be efficient
|
||||
template <typename S>
|
||||
struct ArrayCopyConcreteSrc<vtkm::cont::StorageTagPermutation<vtkm::cont::StorageTagBasic, S>>
|
||||
{
|
||||
using SourceStorageTag = vtkm::cont::StorageTagPermutation<vtkm::cont::StorageTagBasic, S>;
|
||||
template <typename T1, typename T2, typename S2>
|
||||
void operator()(const vtkm::cont::ArrayHandle<T1, SourceStorageTag>& source,
|
||||
vtkm::cont::ArrayHandle<T2, S2>& destination) const
|
||||
{
|
||||
auto indexArray = source.GetStorage().GetIndexArray(source.GetBuffers());
|
||||
auto valueArray = source.GetStorage().GetValueArray(source.GetBuffers());
|
||||
vtkm::cont::UnknownArrayHandle copy =
|
||||
vtkm::cont::internal::MapArrayPermutation(valueArray, indexArray);
|
||||
vtkm::cont::ArrayCopyShallowIfPossible(copy, destination);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace cont
|
||||
} // namespace vtkm
|
||||
|
||||
|
@ -248,12 +248,12 @@ public:
|
||||
return vtkm::cont::internal::CreateBuffers(array1, array2);
|
||||
}
|
||||
|
||||
VTKM_CONT static const ArrayHandleType1& GetArray1(const vtkm::cont::internal::Buffer* buffers)
|
||||
VTKM_CONT static const ArrayHandleType1 GetArray1(const vtkm::cont::internal::Buffer* buffers)
|
||||
{
|
||||
return ArrayHandleType1(Buffers1(buffers));
|
||||
}
|
||||
|
||||
VTKM_CONT static const ArrayHandleType2& GetArray2(const vtkm::cont::internal::Buffer* buffers)
|
||||
VTKM_CONT static const ArrayHandleType2 GetArray2(const vtkm::cont::internal::Buffer* buffers)
|
||||
{
|
||||
return ArrayHandleType2(Buffers2(buffers));
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/cont/ArrayCopy.h>
|
||||
#include <vtkm/cont/ArrayCopyDevice.h>
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/DeviceAdapterList.h>
|
||||
#include <vtkm/cont/Invoker.h>
|
||||
|
||||
@ -145,11 +147,68 @@ struct UnknownCopyFunctor1
|
||||
}
|
||||
};
|
||||
|
||||
void ArrayCopySpecialCase(const vtkm::cont::ArrayHandleIndex& source,
|
||||
const vtkm::cont::UnknownArrayHandle& destination)
|
||||
{
|
||||
if (destination.CanConvert<vtkm::cont::ArrayHandleIndex>())
|
||||
{
|
||||
// Unlikely, but we'll check.
|
||||
destination.AsArrayHandle<vtkm::cont::ArrayHandleIndex>().DeepCopyFrom(source);
|
||||
}
|
||||
else if (destination.IsBaseComponentType<vtkm::Id>())
|
||||
{
|
||||
destination.Allocate(source.GetNumberOfValues());
|
||||
auto dest = destination.ExtractComponent<vtkm::Id>(0, vtkm::CopyFlag::Off);
|
||||
vtkm::cont::ArrayCopyDevice(source, dest);
|
||||
}
|
||||
else if (destination.IsBaseComponentType<vtkm::IdComponent>())
|
||||
{
|
||||
destination.Allocate(source.GetNumberOfValues());
|
||||
auto dest = destination.ExtractComponent<vtkm::IdComponent>(0, vtkm::CopyFlag::Off);
|
||||
vtkm::cont::ArrayCopyDevice(source, dest);
|
||||
}
|
||||
else if (destination.CanConvert<vtkm::cont::ArrayHandle<vtkm::FloatDefault>>())
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> dest;
|
||||
destination.AsArrayHandle(dest);
|
||||
vtkm::cont::ArrayCopyDevice(source, dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initializing something that is probably not really an index. Rather than trace down every
|
||||
// unlikely possibility, just copy to float and then to the final array.
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> dest;
|
||||
vtkm::cont::ArrayCopyDevice(source, dest);
|
||||
vtkm::cont::ArrayCopy(dest, destination);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ArrayHandleType>
|
||||
bool TryArrayCopySpecialCase(const vtkm::cont::UnknownArrayHandle& source,
|
||||
const vtkm::cont::UnknownArrayHandle& destination)
|
||||
{
|
||||
if (source.CanConvert<ArrayHandleType>())
|
||||
{
|
||||
ArrayCopySpecialCase(source.AsArrayHandle<ArrayHandleType>(), destination);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DoUnknownArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
|
||||
const vtkm::cont::UnknownArrayHandle& destination)
|
||||
{
|
||||
if (source.GetNumberOfValues() > 0)
|
||||
{
|
||||
// Try known special cases.
|
||||
if (TryArrayCopySpecialCase<vtkm::cont::ArrayHandleIndex>(source, destination))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
source.CastAndCallWithExtractedArray(UnknownCopyFunctor1{}, destination);
|
||||
}
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user