//============================================================================ // 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 #include #include #include #include #include #include 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 VTKM_EXEC void operator()(const InType& in, OutType& out) const { out = in; } }; struct UnknownCopyOnDevice { bool Called = false; template void operator()(vtkm::cont::DeviceAdapterId device, const vtkm::cont::ArrayHandleRecombineVec& in, const vtkm::cont::ArrayHandleRecombineVec& out) { // Note: ArrayHandleRecombineVec returns the wrong value for IsOnDevice (always true). // This is one of the consequences of ArrayHandleRecombineVec breaking assumptions of // ArrayHandle. It does this by stuffing Buffer objects in another Buffer's meta data // rather than listing them explicitly (where they can be queried). We get around this // by pulling out one of the component arrays and querying that. if (!this->Called && ((device == vtkm::cont::DeviceAdapterTagAny{}) || (in.GetComponentArray(0).IsOnDevice(device) && vtkm::cont::GetRuntimeDeviceTracker().CanRunOn(device)))) { vtkm::cont::Invoker invoke(device); invoke(CopyWorklet{}, in, out); this->Called = true; } } }; struct UnknownCopyFunctor2 { template void operator()(const vtkm::cont::ArrayHandleRecombineVec& out, const vtkm::cont::ArrayHandleRecombineVec& 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 void operator()(const vtkm::cont::ArrayHandleRecombineVec& in, const vtkm::cont::UnknownArrayHandle& out) const { out.Allocate(in.GetNumberOfValues()); this->DoIt(in, out, typename std::is_same::type{}); } template void DoIt(const vtkm::cont::ArrayHandleRecombineVec& in, const vtkm::cont::UnknownArrayHandle& out, std::false_type) const { // Source is not float. if (out.IsBaseComponentType()) { // Arrays have the same base component type. Copy directly. try { UnknownCopyFunctor2{}(out.ExtractArrayFromComponents(vtkm::CopyFlag::Off), in); } catch (vtkm::cont::Error& error) { throw vtkm::cont::ErrorBadType( "Unable to copy to an array of type " + out.GetArrayTypeName() + " using anonymous methods. Try using vtkm::cont::ArrayCopyDevice. " "(Original error: `" + error.GetMessage() + "')"); } } else if (out.IsBaseComponentType()) { // Can copy anything to default float. try { UnknownCopyFunctor2{}( out.ExtractArrayFromComponents(vtkm::CopyFlag::Off), in); } catch (vtkm::cont::Error& error) { throw vtkm::cont::ErrorBadType( "Unable to copy to an array of type " + out.GetArrayTypeName() + " using anonymous methods. Try using vtkm::cont::ArrayCopyDevice. " "(Original error: `" + error.GetMessage() + "')"); } } else { // Arrays have different base types. To reduce the number of template paths from nxn to 3n, // copy first to a temp array of default float. vtkm::cont::UnknownArrayHandle temp = out.NewInstanceFloatBasic(); (*this)(in, temp); vtkm::cont::ArrayCopy(temp, out); } } template void DoIt(const vtkm::cont::ArrayHandleRecombineVec& in, const vtkm::cont::UnknownArrayHandle& out, std::true_type) const { // Source array is FloatDefault. That should be copiable to anything. out.CastAndCallWithExtractedArray(UnknownCopyFunctor2{}, in); } }; void ArrayCopySpecialCase(const vtkm::cont::ArrayHandleIndex& source, const vtkm::cont::UnknownArrayHandle& destination) { if (destination.CanConvert()) { // Unlikely, but we'll check. destination.AsArrayHandle().DeepCopyFrom(source); } else if (destination.IsBaseComponentType()) { destination.Allocate(source.GetNumberOfValues()); auto dest = destination.ExtractComponent(0, vtkm::CopyFlag::Off); vtkm::cont::ArrayCopyDevice(source, dest); } else if (destination.IsBaseComponentType()) { destination.Allocate(source.GetNumberOfValues()); auto dest = destination.ExtractComponent(0, vtkm::CopyFlag::Off); vtkm::cont::ArrayCopyDevice(source, dest); } else if (destination.CanConvert>()) { vtkm::cont::ArrayHandle 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 dest; vtkm::cont::ArrayCopyDevice(source, dest); vtkm::cont::ArrayCopy(dest, destination); } } template bool TryArrayCopySpecialCase(const vtkm::cont::UnknownArrayHandle& source, const vtkm::cont::UnknownArrayHandle& destination) { if (source.CanConvert()) { ArrayCopySpecialCase(source.AsArrayHandle(), 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(source, destination)) { return; } source.CastAndCallWithExtractedArray(UnknownCopyFunctor1{}, destination); } else { destination.ReleaseResources(); } } } // anonymous namespace namespace vtkm { namespace cont { namespace internal { void ArrayCopyUnknown(const vtkm::cont::UnknownArrayHandle& source, vtkm::cont::UnknownArrayHandle& destination) { if (!destination.IsValid()) { destination = source.NewInstanceBasic(); } DoUnknownArrayCopy(source, destination); } void ArrayCopyUnknown(const vtkm::cont::UnknownArrayHandle& source, const vtkm::cont::UnknownArrayHandle& destination) { if (!destination.IsValid()) { throw vtkm::cont::ErrorBadValue( "Attempty to copy to a constant UnknownArrayHandle with no valid array."); } DoUnknownArrayCopy(source, destination); } } // namespace vtkm::cont::internal } // namespace vtkm::cont } // namespace vtkm