mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 01:49:02 +00:00
Merge topic 'fill-stride-arrays'
723c9ed2f Support `Fill` for `ArrayHandleStride` Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !3186
This commit is contained in:
commit
fc92eafb76
22
docs/changelog/fill-stride-arrays.md
Normal file
22
docs/changelog/fill-stride-arrays.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Support `Fill` for `ArrayHandleStride`
|
||||
|
||||
Previously, if you called `Fill` on an `ArrayHandleStride`, you would get
|
||||
an exception that said the feature was not supported. It turns out that
|
||||
filling values is very useful in situations where, for example, you need to
|
||||
initialize an array when processing an unknown type (and thus dealing with
|
||||
extracted components).
|
||||
|
||||
This implementation of `Fill` first attempts to call `Fill` on the
|
||||
contained array. This only works if the stride is set to 1. If this does
|
||||
not work, then the code leverages the precompiled `ArrayCopy`. It does this
|
||||
by first creating a new `ArrayHandleStride` containing the fill value and a
|
||||
modulo of 1 so that value is constantly repeated. It then reconstructs an
|
||||
`ArrayHandleStride` for itself with a modified size and offset to match the
|
||||
start and end indices.
|
||||
|
||||
Referencing the `ArrayCopy` was tricky because it kept creating circular
|
||||
dependencies among `ArrayHandleStride`, `ArrayExtractComponent`, and
|
||||
`UnknownArrayHandle`. These dependencies were broken by having
|
||||
`ArrayHandleStride` directly use the internal `ArrayCopyUnknown` function
|
||||
and to use a forward declaration of `UnknownArrayHandle` rather than
|
||||
including its header.
|
@ -544,9 +544,10 @@ public:
|
||||
|
||||
/// @brief Fills the array with a given value.
|
||||
///
|
||||
/// After calling this method, every entry in the array from `startIndex` to `endIndex`.
|
||||
/// of the array is set to `fillValue`. If `startIndex` or `endIndex` is not specified,
|
||||
/// then the fill happens from the begining or end, respectively.
|
||||
/// After calling this method, every entry in the array from `startIndex` (inclusive)
|
||||
/// to `endIndex` (exclusive) of the array is set to `fillValue`. If `startIndex` or
|
||||
/// `endIndex` is not specified, then the fill happens from the begining or end,
|
||||
/// respectively.
|
||||
///
|
||||
VTKM_CONT void Fill(const ValueType& fillValue,
|
||||
vtkm::Id startIndex,
|
||||
|
@ -11,6 +11,8 @@
|
||||
#define vtk_m_cont_ArrayHandleStride_cxx
|
||||
#include <vtkm/cont/ArrayHandleStride.h>
|
||||
|
||||
#include <vtkm/cont/UnknownArrayHandle.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <vtkm/cont/ArrayHandleBasic.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
#include <vtkm/cont/internal/ArrayCopyUnknown.h>
|
||||
|
||||
#include <vtkm/internal/ArrayPortalBasic.h>
|
||||
|
||||
@ -257,14 +258,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>&,
|
||||
const T&,
|
||||
vtkm::Id,
|
||||
vtkm::Id,
|
||||
vtkm::cont::Token&)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadType("Fill not supported for ArrayHandleStride.");
|
||||
}
|
||||
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
||||
const T& fillValue,
|
||||
vtkm::Id startIndex,
|
||||
vtkm::Id endIndex,
|
||||
vtkm::cont::Token& token);
|
||||
|
||||
VTKM_CONT static ReadPortalType CreateReadPortal(
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
||||
@ -398,6 +396,57 @@ vtkm::cont::ArrayHandleStride<T> make_ArrayHandleStride(
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
VTKM_CONT inline void Storage<T, vtkm::cont::StorageTagStride>::Fill(
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
||||
const T& fillValue,
|
||||
vtkm::Id startIndex,
|
||||
vtkm::Id endIndex,
|
||||
vtkm::cont::Token& token)
|
||||
{
|
||||
const StrideInfo& info = GetInfo(buffers);
|
||||
vtkm::cont::ArrayHandleBasic<T> basicArray = GetBasicArray(buffers);
|
||||
if ((info.Stride == 1) && (info.Modulo == 0) && (info.Divisor <= 1))
|
||||
{
|
||||
// Standard stride in array allows directly calling fill on the basic array.
|
||||
basicArray.Fill(fillValue, startIndex + info.Offset, endIndex + info.Offset, token);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The fill does not necessarily cover a contiguous region. We have to have a loop
|
||||
// to set it. But we are not allowed to write device code here. Instead, create
|
||||
// a stride array containing the fill value with a modulo of 1 so that this fill
|
||||
// value repeates. Then feed this into a precompiled array copy that supports
|
||||
// stride arrays.
|
||||
const vtkm::Id numFill = endIndex - startIndex;
|
||||
auto fillValueArray = vtkm::cont::make_ArrayHandle({ fillValue });
|
||||
vtkm::cont::ArrayHandleStride<T> constantArray(fillValueArray, numFill, 1, 0, 1, 1);
|
||||
vtkm::cont::ArrayHandleStride<T> outputView(GetBasicArray(buffers),
|
||||
numFill,
|
||||
info.Stride,
|
||||
info.ArrayIndex(startIndex),
|
||||
info.Modulo,
|
||||
info.Divisor);
|
||||
// To prevent circular dependencies, this header file does not actually include
|
||||
// UnknownArrayHandle.h. Thus, it is possible to get a compile error on the following
|
||||
// line for using a declared but not defined `UnknownArrayHandle`. In the unlikely
|
||||
// event this occurs, simply include `vtkm/cont/UnknownArrayHandle.h` somewhere up the
|
||||
// include chain.
|
||||
vtkm::cont::internal::ArrayCopyUnknown(constantArray, outputView);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::cont::internal
|
||||
|
||||
//=============================================================================
|
||||
// Specializations of serialization related classes
|
||||
/// @cond SERIALIZATION
|
||||
|
@ -10,14 +10,18 @@
|
||||
#ifndef vtk_m_cont_internal_ArrayCopyUnknown_h
|
||||
#define vtk_m_cont_internal_ArrayCopyUnknown_h
|
||||
|
||||
#include <vtkm/cont/UnknownArrayHandle.h>
|
||||
|
||||
#include <vtkm/cont/vtkm_cont_export.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
// Rather than include UnknownArrayHandle.h, we just forward declare the class so
|
||||
// we can declare our functions and prevent any circular header dependencies from
|
||||
// core classes.
|
||||
class UnknownArrayHandle;
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
|
@ -292,6 +292,23 @@ void TryCopy()
|
||||
TestValues(input, output);
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "constant -> extracted component" << std::endl;
|
||||
using ComponentType = typename VTraits::BaseComponentType;
|
||||
vtkm::cont::ArrayHandle<ValueType> output;
|
||||
output.Allocate(ARRAY_SIZE);
|
||||
ValueType invalue = TestValue(7, ValueType{});
|
||||
for (vtkm::IdComponent component = 0; component < VTraits::NUM_COMPONENTS; ++component)
|
||||
{
|
||||
vtkm::cont::ArrayHandleConstant<ComponentType> input(
|
||||
VTraits::GetComponent(invalue, component), ARRAY_SIZE);
|
||||
auto extractedComponent =
|
||||
vtkm::cont::ArrayExtractComponent(output, component, vtkm::CopyFlag::Off);
|
||||
vtkm::cont::ArrayCopy(input, extractedComponent);
|
||||
}
|
||||
TestValues(vtkm::cont::make_ArrayHandleConstant(invalue, ARRAY_SIZE), output);
|
||||
}
|
||||
|
||||
// Test the copy methods in UnknownArrayHandle. Although this would be appropriate in
|
||||
// UnitTestUnknownArrayHandle, it is easier to test copies here.
|
||||
{
|
||||
|
@ -155,6 +155,22 @@ void CheckOutputArray(
|
||||
GetVecFlatIndex(outValue, numComponents - componentId - 1)));
|
||||
}
|
||||
}
|
||||
|
||||
// Check to make sure you can fill extracted components with a constant value.
|
||||
for (vtkm::IdComponent componentId = 0; componentId < numComponents; ++componentId)
|
||||
{
|
||||
auto componentArray =
|
||||
vtkm::cont::ArrayExtractComponent(outputArray, componentId, vtkm::CopyFlag::Off);
|
||||
componentArray.Fill(TestValue(componentId, ComponentType{}));
|
||||
}
|
||||
for (vtkm::IdComponent componentId = 0; componentId < numComponents; ++componentId)
|
||||
{
|
||||
auto componentArray =
|
||||
vtkm::cont::ArrayExtractComponent(outputArray, componentId, vtkm::CopyFlag::Off);
|
||||
auto constantArray = vtkm::cont::make_ArrayHandleConstant(
|
||||
TestValue(componentId, ComponentType{}), originalArray.GetNumberOfValues());
|
||||
VTKM_TEST_ASSERT(test_equal_ArrayHandles(componentArray, constantArray));
|
||||
}
|
||||
}
|
||||
|
||||
void DoTest()
|
||||
|
Loading…
Reference in New Issue
Block a user