vtk-m/vtkm/cont/ArrayGetValues.cxx
Kenneth Moreland 5b34e6f70b Better fallback for ArrayGetValue
To avoid having to use a device compiler every time you wish to use
`ArrayGetValue`, the actual implementation is compiled into the `vtkm_cont`
library. To allow this to work for all the templated versions of
`ArrayHandle`, the implementation uses the extract component features of
`UnknownArrayHandle`. This works for most common arrays, but not all
arrays.

For arrays that cannot be directly represented by an `ArrayHandleStride`,
the fallback is bad. The entire array has to be pulled to the host and then
copied serially to a basic array.

For `ArrayGetValue`, this is just silly. So, for arrays that cannot be
simply represented by `ArrayHandleStride`, make a fallback that just uses
`ReadPortal` to get the data. Often this is not the most efficient method,
but it is better than the current alternative.
2022-01-03 10:08:39 -07:00

82 lines
3.1 KiB
C++

//============================================================================
// 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/ArrayGetValues.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/UnknownArrayHandle.h>
#include <vtkm/List.h>
#include <vtkm/TypeList.h>
void vtkm::cont::internal::ArrayGetValuesImpl(const vtkm::cont::UnknownArrayHandle& ids,
const vtkm::cont::UnknownArrayHandle& data,
const vtkm::cont::UnknownArrayHandle& output,
std::false_type)
{
auto idArray = ids.ExtractComponent<vtkm::Id>(0, vtkm::CopyFlag::On);
output.Allocate(ids.GetNumberOfValues());
bool copied = false;
vtkm::ListForEach(
[&](auto base) {
using T = decltype(base);
if (!copied && data.IsBaseComponentType<T>())
{
vtkm::IdComponent numComponents = data.GetNumberOfComponentsFlat();
VTKM_ASSERT(output.GetNumberOfComponentsFlat() == numComponents);
for (vtkm::IdComponent componentIdx = 0; componentIdx < numComponents; ++componentIdx)
{
auto dataArray = data.ExtractComponent<T>(componentIdx, vtkm::CopyFlag::On);
auto outputArray = output.ExtractComponent<T>(componentIdx, vtkm::CopyFlag::Off);
auto permutedArray = vtkm::cont::make_ArrayHandlePermutation(idArray, dataArray);
bool copiedComponent = false;
if (!dataArray.IsOnHost())
{
copiedComponent = vtkm::cont::TryExecute([&](auto device) {
if (dataArray.IsOnDevice(device))
{
vtkm::cont::DeviceAdapterAlgorithm<decltype(device)>::Copy(permutedArray,
outputArray);
return true;
}
return false;
});
}
if (!copiedComponent)
{ // Fallback to a control-side copy if the device copy fails or if the device
// is undefined or if the data were already on the host. In this case, the
// best we can do is grab the portals and copy one at a time on the host with
// a for loop.
const vtkm::Id numVals = ids.GetNumberOfValues();
auto inPortal = permutedArray.ReadPortal();
auto outPortal = outputArray.WritePortal();
for (vtkm::Id i = 0; i < numVals; ++i)
{
outPortal.Set(i, inPortal.Get(i));
}
}
}
copied = true;
}
},
vtkm::TypeListBaseC{});
if (!copied)
{
throw vtkm::cont::ErrorBadType("Unable to get values from array of type " +
data.GetArrayTypeName());
}
}