Add general ArrayCopy between UnknownArrayHandles

Add an overload of `ArrayCopy` that takes `UnknownArrayHandle`s and
copies them for (almost) any `ArrayHandle` type.

The code uses `CastAndCallWithExtractedArray` to reduce the total number
of copy conditions to about 100, which are all precompiled into the
library. On a debug build on my mac, this creates a .o file of 21MB.
That's not great, but not terrible. Hopefully, this can be used to
consolidate copy implementations elsewhere.
This commit is contained in:
Kenneth Moreland 2021-01-14 15:25:09 -07:00
parent 26ea2ab420
commit 916a01d7b9
5 changed files with 115 additions and 38 deletions

92
vtkm/cont/ArrayCopy.cxx Normal file

@ -0,0 +1,92 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/DeviceAdapterList.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace
{
// Use a worklet because device adapter copies often have an issue with casting the values from the
// `ArrayHandleRecomineVec` that comes from `UnknownArrayHandle::CastAndCallWithExtractedArray`.
struct CopyWorklet : vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn, FieldOut);
using ExecutionSignature = void(_1, _2);
using InputDomain = _1;
template <typename InType, typename OutType>
void operator()(const InType& in, OutType& out) const
{
out = in;
}
};
struct UnknownCopyOnDevice
{
bool Called = false;
template <typename InArrayType, typename OutArrayType>
void operator()(vtkm::cont::DeviceAdapterId device,
const InArrayType& in,
const OutArrayType& out)
{
if (!this->Called && ((device == vtkm::cont::DeviceAdapterTagAny{}) || (in.IsOnDevice(device))))
{
vtkm::cont::Invoker invoke(device);
invoke(CopyWorklet{}, in, out);
this->Called = true;
}
}
};
struct UnknownCopyFunctor2
{
template <typename OutArrayType, typename InArrayType>
void operator()(const OutArrayType& out, const InArrayType& in) const
{
UnknownCopyOnDevice doCopy;
// Try to copy on a device that the data are already on.
vtkm::ListForEach(doCopy, VTKM_DEFAULT_DEVICE_ADAPTER_LIST{}, in, out);
// If it was not on any device, call one more time with any adapter to copy wherever.
doCopy(vtkm::cont::DeviceAdapterTagAny{}, in, out);
}
};
struct UnknownCopyFunctor1
{
template <typename InArrayType>
void operator()(const InArrayType& in, const vtkm::cont::UnknownArrayHandle& out) const
{
out.Allocate(in.GetNumberOfValues());
out.CastAndCallWithExtractedArray(UnknownCopyFunctor2{}, in);
}
};
} // anonymous namespace
namespace vtkm
{
namespace cont
{
void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination)
{
destination.CastAndCallWithExtractedArray(UnknownCopyFunctor1{}, source);
}
}
} // namespace vtkm::cont

@ -15,7 +15,7 @@
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/cont/ErrorExecution.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/VariantArrayHandle.h>
#include <vtkm/cont/UnknownArrayHandle.h>
#include <vtkm/cont/internal/ArrayHandleDeprecated.h>
@ -160,46 +160,25 @@ VTKM_CONT void ArrayCopy(const vtkm::cont::ArrayHandle<InValueType, InStorage>&
detail::ArrayCopyImpl(source, destination, std::integral_constant<bool, !IsOldStyle::value>{});
}
namespace detail
{
struct ArrayCopyFunctor
VTKM_CONT_EXPORT void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination);
template <typename T, typename S>
VTKM_CONT void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
vtkm::cont::ArrayHandle<T, S>& destination)
{
template <typename InValueType, typename InStorage, typename OutValueType, typename OutStorage>
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<InValueType, InStorage>& source,
vtkm::cont::ArrayHandle<OutValueType, OutStorage>& destination) const
using DestType = vtkm::cont::ArrayHandle<T, S>;
if (source.IsType<DestType>())
{
vtkm::cont::ArrayCopy(source, destination);
ArrayCopy(source.AsArrayHandle<DestType>(), destination);
}
else
{
ArrayCopy(source, vtkm::cont::UnknownArrayHandle(destination));
}
};
} // namespace detail
/// \brief Deep copies data in an `UncertainArrayHandle` to an array of a known type.
///
/// This form of `ArrayCopy` can be used to copy data from an unknown array type to
/// an array of a known type. Note that regardless of the source type, the data will
/// be deep copied.
///
template <typename InValueList, typename InStorageList, typename OutValue, typename OutStorage>
VTKM_CONT void ArrayCopy(const vtkm::cont::UncertainArrayHandle<InValueList, InStorageList>& src,
vtkm::cont::ArrayHandle<OutValue, OutStorage>& dest)
{
src.CastAndCall(detail::ArrayCopyFunctor{}, dest);
}
/// \brief Deep copies data in a `VariantArrayHandle` to an array of a known type.
///
/// This form of `ArrayCopy` can be used to copy data from an unknown array type to
/// an array of a known type. Note that regardless of the source type, the data will
/// be deep copied.
///
template <typename InTypeList, typename OutValueType, typename OutStorage>
VTKM_CONT void ArrayCopy(const vtkm::cont::VariantArrayHandleBase<InTypeList>& source,
vtkm::cont::ArrayHandle<OutValueType, OutStorage>& destination)
{
source.CastAndCall(detail::ArrayCopyFunctor{}, destination);
}
}
} // namespace vtkm::cont

@ -160,9 +160,10 @@ set(sources
TryExecute.cxx
)
# This list of sources has code that uses devices and so might need to be
# compiled with a device-specific compiler (like CUDA).
set(device_sources
# This list of sources has code that uses devices and so might need to be
# compiled with a device-specific compiler (like CUDA).
set(device_sources
ArrayCopy.cxx
ArrayRangeCompute.cxx
AssignerPartitionedDataSet.cxx
BoundsCompute.cxx

@ -18,6 +18,7 @@
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandleRecombineVec.h>
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/cont/CastAndCall.h>
#include <vtkm/cont/DefaultTypes.h>
#include <memory>

@ -59,6 +59,10 @@ void TryCopy()
vtkm::cont::ArrayHandle<ValueType> output;
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
output.ReleaseResources();
vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle(input), output);
TestValues(input, output);
}
{