mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 01:49:02 +00:00
Merge branch 'master' into hdf5_image_io
This commit is contained in:
commit
ca0ce4de7b
@ -32,6 +32,7 @@
|
||||
# - tbb
|
||||
# - openmp
|
||||
# - mpich2
|
||||
# - hdf5
|
||||
# * .gitlab/ci/docker/ubuntu1804/cuda11.1/
|
||||
# - cuda
|
||||
# - gcc 7
|
||||
@ -75,8 +76,7 @@
|
||||
- .docker_image
|
||||
|
||||
.ubuntu1804: &ubuntu1804
|
||||
# image: "kitware/vtkm:ci-ubuntu1804-20201016"
|
||||
image: "ollielo/vtkm:ci-ubuntu1804-01042020"
|
||||
image: "kitware/vtkm:ci-ubuntu1804-20210107"
|
||||
extends:
|
||||
- .docker_image
|
||||
|
||||
|
@ -29,6 +29,10 @@ foreach(option IN LISTS options)
|
||||
elseif(vtk_types STREQUAL option)
|
||||
set(VTKm_USE_DEFAULT_TYPES_FOR_VTK "ON" CACHE STRING "")
|
||||
|
||||
elseif(ascent_types STREQUAL option)
|
||||
# Note: ascent_types also requires 32bit_ids and 64bit_floats
|
||||
set(VTKm_USE_DEFAULT_TYPES_FOR_ASCENT "ON" CACHE STRING "")
|
||||
|
||||
elseif(32bit_ids STREQUAL option)
|
||||
set(VTKm_USE_64BIT_IDS "OFF" CACHE STRING "")
|
||||
|
||||
|
@ -10,7 +10,7 @@ readonly tarball="$filename.tar.gz"
|
||||
cd .gitlab
|
||||
|
||||
echo "$sha256sum $tarball" > sccache.sha256sum
|
||||
curl -OL "https://github.com/robertmaynard/sccache/releases/download/$version/$tarball"
|
||||
curl --insecure -OL "https://github.com/robertmaynard/sccache/releases/download/$version/$tarball"
|
||||
sha256sum --check sccache.sha256sum
|
||||
tar xf "$tarball"
|
||||
#mv "$filename/sccache" .
|
||||
|
@ -18,7 +18,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
software-properties-common
|
||||
|
||||
# extra dependencies for charm machine
|
||||
#RUN add-apt-repository ppa:jonathonf/gcc-9.2
|
||||
RUN add-apt-repository ppa:jonathonf/gcc
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
clang-8 \
|
||||
|
@ -17,7 +17,7 @@ build:ubuntu1604_gcc5:
|
||||
CC: "gcc-5"
|
||||
CXX: "g++-5"
|
||||
CMAKE_BUILD_TYPE: RelWithDebInfo
|
||||
VTKM_SETTINGS: "cuda+pascal+no_virtual"
|
||||
VTKM_SETTINGS: "cuda+pascal+no_virtual+ascent_types+32bit_ids+64bit_floats"
|
||||
|
||||
test:ubuntu1604_gcc5:
|
||||
tags:
|
||||
|
@ -33,7 +33,7 @@ function(vtkm_get_kit_name kitvar)
|
||||
# Optional second argument to get dir_prefix.
|
||||
if (${ARGC} GREATER 1)
|
||||
set(${ARGV1} "${dir_prefix}" PARENT_SCOPE)
|
||||
endif (${ARGC} GREATER 1)
|
||||
endif ()
|
||||
endfunction(vtkm_get_kit_name)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
@ -226,7 +226,7 @@ if (VTKm_ENABLE_TESTING)
|
||||
# Setup compiler flags for dynamic analysis if needed
|
||||
include(testing/VTKmCompilerDynamicAnalysisFlags)
|
||||
|
||||
endif (VTKm_ENABLE_TESTING)
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Check basic type sizes.
|
||||
|
3
data/baseline/contour-tangle.png
Normal file
3
data/baseline/contour-tangle.png
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b4f049b4f0e79a27ebbdab187325db55653abe2ce661c8f1d2f3fcb413e3b961
|
||||
size 10883
|
3
data/baseline/contour-uniform.png
Normal file
3
data/baseline/contour-uniform.png
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8c22f2d4e19191ff05d9dc52ea740269fcdfe129b9d100ea8db6d4cbb989b161
|
||||
size 9652
|
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c1a54c159483076a2eed1f7cf8f8d947e6ec59dcfbd8ed41355e92cf052d344e
|
||||
size 19884
|
26
docs/changelog/recombine-vec-array.md
Normal file
26
docs/changelog/recombine-vec-array.md
Normal file
@ -0,0 +1,26 @@
|
||||
# Recombine extracted component arrays from unknown arrays
|
||||
|
||||
Building on the recent capability to [extract component arrays from unknown
|
||||
arrays](array-extract-component.md), there is now also the ability to
|
||||
recombine these extracted arrays to a single `ArrayHandle`. It might seem
|
||||
counterintuitive to break an `ArrayHandle` into component arrays and then
|
||||
combine the component arrays back into a single `ArrayHandle`, but this is
|
||||
a very handy way to run algorithms without knowing the exact `ArrayHandle`
|
||||
type.
|
||||
|
||||
Recall that when extracting a component array from an `UnknownArrayHandle`
|
||||
you only need to know the base component of the value type of the contained
|
||||
`ArrayHandle`. That makes extracting a component array independent from
|
||||
either the size of any `Vec` value type and any storage type.
|
||||
|
||||
The added `UnknownArrayHandle::ExtractArrayFromComponents` method allows
|
||||
you to use the functionality to transform the unknown array handle to a
|
||||
form of `ArrayHandle` that depends only on this base component type. This
|
||||
method internally uses a new `ArrayHandleRecombineVec` class, but this
|
||||
class is mostly intended for internal use by this class.
|
||||
|
||||
As an added convenience, `UnknownArrayHandle` now also provides the
|
||||
`CastAndCallWithExtractedArray` method. This method works like other
|
||||
`CastAndCall`s except that it uses the `ExtractArrayFromComponents` feature
|
||||
to allow you to handle most `ArrayHandle` types with few template
|
||||
instances.
|
22
docs/changelog/soa-array-default.md
Normal file
22
docs/changelog/soa-array-default.md
Normal file
@ -0,0 +1,22 @@
|
||||
Support `ArrayHandleSOA` as a "default" array
|
||||
|
||||
Many programs, particularly simulations, store fields of vectors in
|
||||
separate arrays for each component. This maps to the storage of
|
||||
`ArrayHandleSOA`. The VTK-m code tends to prefer the AOS storage (which is
|
||||
what is implemented in `ArrayHandleBasic`, and the behavior of which is
|
||||
inherited from VTK). VTK-m should better support adding `ArrayHandleSOA` as
|
||||
one of the types.
|
||||
|
||||
We now have a set of default types for Ascent that uses SOA as one of the
|
||||
basic types.
|
||||
|
||||
Part of this change includes an intentional feature regression of
|
||||
`ArrayHandleSOA` to only support value types of `Vec`. Previously, scalar
|
||||
types were supported. However, the behavior of `ArrayHandleSOA` is exactly
|
||||
the same as `ArrayHandleBasic`, except a lot more template code has to be
|
||||
generated. That itself is not a huge deal, but because you have 2 types
|
||||
that essentially do the same thing, a lot of template code in VTK-m would
|
||||
unwind to create two separate code paths that do the same thing with the
|
||||
same data. To avoid creating those code paths, we simply make any use of
|
||||
`ArrayHandleSOA` without a `Vec` value invalid. This will prevent VTK-m
|
||||
from creating those code paths.
|
@ -463,7 +463,7 @@ VTKM_EXEC_CONT inline vtkm::UInt64 AtomicLoadImpl(vtkm::UInt64* const addr, vtkm
|
||||
|
||||
VTKM_EXEC_CONT inline void AtomicStoreImpl(vtkm::UInt8* addr,
|
||||
vtkm::UInt8 val,
|
||||
vtkm::MemoryOrder order)
|
||||
vtkm::MemoryOrder vtkmNotUsed(order))
|
||||
{
|
||||
// There doesn't seem to be an atomic store instruction in the windows
|
||||
// API, so just exchange and discard the result.
|
||||
@ -471,7 +471,7 @@ VTKM_EXEC_CONT inline void AtomicStoreImpl(vtkm::UInt8* addr,
|
||||
}
|
||||
VTKM_EXEC_CONT inline void AtomicStoreImpl(vtkm::UInt16* addr,
|
||||
vtkm::UInt16 val,
|
||||
vtkm::MemoryOrder order)
|
||||
vtkm::MemoryOrder vtkmNotUsed(order))
|
||||
{
|
||||
// There doesn't seem to be an atomic store instruction in the windows
|
||||
// API, so just exchange and discard the result.
|
||||
@ -499,31 +499,31 @@ VTKM_EXEC_CONT inline void AtomicStoreImpl(vtkm::UInt64* addr,
|
||||
winName##suffix(reinterpret_cast<volatile winType*>(addr), BitCast<winType>(arg))); \
|
||||
}
|
||||
|
||||
#define VTKM_ATOMIC_OPS_FOR_TYPE(vtkmType, winType, suffix) \
|
||||
VTKM_ATOMIC_OP(AtomicAddImpl, _InterlockedExchangeAdd, vtkmType, winType, suffix) \
|
||||
VTKM_ATOMIC_OP(AtomicAndImpl, _InterlockedAnd, vtkmType, winType, suffix) \
|
||||
VTKM_ATOMIC_OP(AtomicOrImpl, _InterlockedOr, vtkmType, winType, suffix) \
|
||||
VTKM_ATOMIC_OP(AtomicXorImpl, _InterlockedXor, vtkmType, winType, suffix) \
|
||||
VTKM_EXEC_CONT inline vtkmType AtomicNotImpl(vtkmType* addr, vtkm::MemoryOrder order) \
|
||||
{ \
|
||||
return AtomicXorImpl(addr, static_cast<vtkmType>(~vtkmType{ 0u }), order); \
|
||||
} \
|
||||
VTKM_EXEC_CONT inline bool AtomicCompareExchangeImpl( \
|
||||
vtkmType* addr, vtkmType* expected, vtkmType desired, vtkm::MemoryOrder order) \
|
||||
{ \
|
||||
vtkmType result = BitCast<vtkmType>( \
|
||||
_InterlockedCompareExchange##suffix(reinterpret_cast<volatile winType*>(addr), \
|
||||
BitCast<winType>(desired), \
|
||||
BitCast<winType>(*expected))); \
|
||||
if (result == *expected) \
|
||||
{ \
|
||||
return true; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
*expected = result; \
|
||||
return false; \
|
||||
} \
|
||||
#define VTKM_ATOMIC_OPS_FOR_TYPE(vtkmType, winType, suffix) \
|
||||
VTKM_ATOMIC_OP(AtomicAddImpl, _InterlockedExchangeAdd, vtkmType, winType, suffix) \
|
||||
VTKM_ATOMIC_OP(AtomicAndImpl, _InterlockedAnd, vtkmType, winType, suffix) \
|
||||
VTKM_ATOMIC_OP(AtomicOrImpl, _InterlockedOr, vtkmType, winType, suffix) \
|
||||
VTKM_ATOMIC_OP(AtomicXorImpl, _InterlockedXor, vtkmType, winType, suffix) \
|
||||
VTKM_EXEC_CONT inline vtkmType AtomicNotImpl(vtkmType* addr, vtkm::MemoryOrder order) \
|
||||
{ \
|
||||
return AtomicXorImpl(addr, static_cast<vtkmType>(~vtkmType{ 0u }), order); \
|
||||
} \
|
||||
VTKM_EXEC_CONT inline bool AtomicCompareExchangeImpl( \
|
||||
vtkmType* addr, vtkmType* expected, vtkmType desired, vtkm::MemoryOrder vtkmNotUsed(order)) \
|
||||
{ \
|
||||
vtkmType result = BitCast<vtkmType>( \
|
||||
_InterlockedCompareExchange##suffix(reinterpret_cast<volatile winType*>(addr), \
|
||||
BitCast<winType>(desired), \
|
||||
BitCast<winType>(*expected))); \
|
||||
if (result == *expected) \
|
||||
{ \
|
||||
return true; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
*expected = result; \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
||||
VTKM_ATOMIC_OPS_FOR_TYPE(vtkm::UInt8, CHAR, 8)
|
||||
|
@ -1722,7 +1722,7 @@ static inline VTKM_EXEC_CONT vtkm::Float64 Max(vtkm::Float64 x, vtkm::Float64 y)
|
||||
///
|
||||
template <typename T>
|
||||
static inline VTKM_EXEC_CONT T Min(const T& x, const T& y);
|
||||
#ifdef VTKM_USE_STL
|
||||
#if defined(VTKM_USE_STL) && !defined(VTKM_HIP)
|
||||
static inline VTKM_EXEC_CONT vtkm::Float32 Min(vtkm::Float32 x, vtkm::Float32 y)
|
||||
{
|
||||
return (std::min)(x, y);
|
||||
@ -1731,7 +1731,7 @@ static inline VTKM_EXEC_CONT vtkm::Float64 Min(vtkm::Float64 x, vtkm::Float64 y)
|
||||
{
|
||||
return (std::min)(x, y);
|
||||
}
|
||||
#else // !VTKM_USE_STL
|
||||
#else // !VTKM_USE_STL OR HIP
|
||||
static inline VTKM_EXEC_CONT vtkm::Float32 Min(vtkm::Float32 x, vtkm::Float32 y)
|
||||
{
|
||||
#ifdef VTKM_CUDA
|
||||
|
@ -564,10 +564,10 @@ $#
|
||||
///
|
||||
template <typename T>
|
||||
static inline VTKM_EXEC_CONT T Min(const T& x, const T& y);
|
||||
#ifdef VTKM_USE_STL
|
||||
#if defined(VTKM_USE_STL) && !defined(VTKM_HIP)
|
||||
$binary_template_function('Min', '(std::min)(x, y)')\
|
||||
$#
|
||||
#else // !VTKM_USE_STL
|
||||
#else // !VTKM_USE_STL OR HIP
|
||||
$binary_math_function('Min', 'fmin')\
|
||||
$#
|
||||
#endif // !VTKM_USE_STL
|
||||
|
@ -86,7 +86,12 @@ using TypeListField = vtkm::List<vtkm::Float32,
|
||||
vtkm::Vec4f_64>;
|
||||
|
||||
/// A list of all scalars defined in vtkm/Types.h. A scalar is a type that
|
||||
/// holds a single number.
|
||||
/// holds a single number. This should containing all true variations of
|
||||
/// scalars, but there might be some arithmetic C types not included. For
|
||||
/// example, this list contains `signed char`, and `unsigned char`, but not
|
||||
/// `char` as one of those types will behave the same as it. Two of the three
|
||||
/// types behave the same, but be aware that template resolution will treat
|
||||
/// them differently.
|
||||
///
|
||||
using TypeListScalarAll = vtkm::List<vtkm::Int8,
|
||||
vtkm::UInt8,
|
||||
@ -97,12 +102,16 @@ using TypeListScalarAll = vtkm::List<vtkm::Int8,
|
||||
vtkm::Int64,
|
||||
vtkm::UInt64,
|
||||
vtkm::Float32,
|
||||
vtkm::Float64,
|
||||
// Other base C types that are the same as above but
|
||||
// recognized as different by the compiler
|
||||
char,
|
||||
signed VTKM_UNUSED_INT_TYPE,
|
||||
unsigned VTKM_UNUSED_INT_TYPE>;
|
||||
vtkm::Float64>;
|
||||
|
||||
// A list that containes all the base arithmetric C types (i.e. char, int, float, etc.).
|
||||
// The list contains C types that are functionally equivalent but considered different
|
||||
// types (e.g. it contains both `char` and `signed char`).
|
||||
using TypeListBaseC = vtkm::ListAppend<
|
||||
vtkm::TypeListScalarAll,
|
||||
// Other base C types that are the same as above but
|
||||
// recognized as different by the compiler
|
||||
vtkm::List<bool, char, signed VTKM_UNUSED_INT_TYPE, unsigned VTKM_UNUSED_INT_TYPE>>;
|
||||
|
||||
/// A list of the most commonly use Vec classes. Specifically, these are
|
||||
/// vectors of size 2, 3, or 4 containing either unsigned bytes, signed
|
||||
|
42
vtkm/Types.h
42
vtkm/Types.h
@ -343,15 +343,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OtherComponentType, typename OtherVecType>
|
||||
VTKM_EXEC_CONT DerivedClass& operator=(
|
||||
const vtkm::detail::VecBaseCommon<OtherComponentType, OtherVecType>& src)
|
||||
// Only works with Vec-like objects with operator[] and GetNumberOfComponents().
|
||||
template <typename OtherVecType>
|
||||
VTKM_EXEC_CONT DerivedClass& operator=(const OtherVecType& src)
|
||||
{
|
||||
const OtherVecType& srcDerived = static_cast<const OtherVecType&>(src);
|
||||
VTKM_ASSERT(this->NumComponents() == srcDerived.GetNumberOfComponents());
|
||||
VTKM_ASSERT(this->NumComponents() == src.GetNumberOfComponents());
|
||||
for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
|
||||
{
|
||||
this->Component(i) = OtherComponentType(srcDerived[i]);
|
||||
this->Component(i) = src[i];
|
||||
}
|
||||
return this->Derived();
|
||||
}
|
||||
@ -413,14 +412,12 @@ public:
|
||||
}
|
||||
|
||||
template <typename OtherClass>
|
||||
inline VTKM_EXEC_CONT DerivedClass& operator+=(
|
||||
const VecBaseCommon<ComponentType, OtherClass>& other)
|
||||
inline VTKM_EXEC_CONT DerivedClass& operator+=(const OtherClass& other)
|
||||
{
|
||||
const OtherClass& other_derived = static_cast<const OtherClass&>(other);
|
||||
VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
|
||||
VTKM_ASSERT(this->NumComponents() == other.GetNumberOfComponents());
|
||||
for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
|
||||
{
|
||||
this->Component(i) += other_derived[i];
|
||||
this->Component(i) += other[i];
|
||||
}
|
||||
return this->Derived();
|
||||
}
|
||||
@ -439,14 +436,12 @@ public:
|
||||
}
|
||||
|
||||
template <typename OtherClass>
|
||||
inline VTKM_EXEC_CONT DerivedClass& operator-=(
|
||||
const VecBaseCommon<ComponentType, OtherClass>& other)
|
||||
inline VTKM_EXEC_CONT DerivedClass& operator-=(const OtherClass& other)
|
||||
{
|
||||
const OtherClass& other_derived = static_cast<const OtherClass&>(other);
|
||||
VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
|
||||
VTKM_ASSERT(this->NumComponents() == other.GetNumberOfComponents());
|
||||
for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
|
||||
{
|
||||
this->Component(i) -= other_derived[i];
|
||||
this->Component(i) -= other[i];
|
||||
}
|
||||
return this->Derived();
|
||||
}
|
||||
@ -464,14 +459,12 @@ public:
|
||||
}
|
||||
|
||||
template <typename OtherClass>
|
||||
inline VTKM_EXEC_CONT DerivedClass& operator*=(
|
||||
const VecBaseCommon<ComponentType, OtherClass>& other)
|
||||
inline VTKM_EXEC_CONT DerivedClass& operator*=(const OtherClass& other)
|
||||
{
|
||||
const OtherClass& other_derived = static_cast<const OtherClass&>(other);
|
||||
VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
|
||||
VTKM_ASSERT(this->NumComponents() == other.GetNumberOfComponents());
|
||||
for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
|
||||
{
|
||||
this->Component(i) *= other_derived[i];
|
||||
this->Component(i) *= other[i];
|
||||
}
|
||||
return this->Derived();
|
||||
}
|
||||
@ -489,13 +482,12 @@ public:
|
||||
}
|
||||
|
||||
template <typename OtherClass>
|
||||
VTKM_EXEC_CONT DerivedClass& operator/=(const VecBaseCommon<ComponentType, OtherClass>& other)
|
||||
VTKM_EXEC_CONT DerivedClass& operator/=(const OtherClass& other)
|
||||
{
|
||||
const OtherClass& other_derived = static_cast<const OtherClass&>(other);
|
||||
VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
|
||||
VTKM_ASSERT(this->NumComponents() == other.GetNumberOfComponents());
|
||||
for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
|
||||
{
|
||||
this->Component(i) /= other_derived[i];
|
||||
this->Component(i) /= other[i];
|
||||
}
|
||||
return this->Derived();
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
|
||||
#include <vtkm/cont/BitField.h>
|
||||
#include <vtkm/cont/DeviceAdapter.h>
|
||||
#include <vtkm/cont/ExecutionObjectBase.h>
|
||||
#include <vtkm/cont/Token.h>
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include <vtkm/cont/ErrorExecution.h>
|
||||
#include <vtkm/cont/Logging.h>
|
||||
|
||||
#include <vtkm/cont/internal/ArrayHandleDeprecated.h>
|
||||
|
||||
#include <vtkm/cont/vtkm_cont_export.h>
|
||||
|
||||
// TODO: When virtual arrays are available, compile the implementation in a .cxx/.cu file. Common
|
||||
@ -149,11 +151,12 @@ VTKM_CONT void ArrayCopy(const vtkm::cont::ArrayHandle<InValueType, InStorage>&
|
||||
"Cannot copy to a read-only array with a different "
|
||||
"type than the source.");
|
||||
|
||||
using IsNewStyle =
|
||||
std::is_base_of<vtkm::cont::ArrayHandleNewStyle<InValueType, InStorage>, InArrayType>;
|
||||
using IsOldStyle =
|
||||
std::is_base_of<vtkm::cont::internal::ArrayHandleDeprecated<InValueType, InStorage>,
|
||||
InArrayType>;
|
||||
|
||||
// Static dispatch cases 1 & 2
|
||||
detail::ArrayCopyImpl(source, destination, std::integral_constant<bool, IsNewStyle::value>{});
|
||||
detail::ArrayCopyImpl(source, destination, std::integral_constant<bool, !IsOldStyle::value>{});
|
||||
}
|
||||
|
||||
// Forward declaration
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <vtkm/Flags.h>
|
||||
#include <vtkm/Types.h>
|
||||
|
||||
#include <vtkm/cont/ArrayPortalToIterators.h>
|
||||
#include <vtkm/cont/DeviceAdapterList.h>
|
||||
#include <vtkm/cont/ErrorBadValue.h>
|
||||
#include <vtkm/cont/ErrorInternal.h>
|
||||
@ -33,10 +32,7 @@
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <vtkm/cont/internal/ArrayHandleExecutionManager.h>
|
||||
#include <vtkm/cont/internal/ArrayPortalFromIterators.h>
|
||||
#include <vtkm/cont/internal/Buffer.h>
|
||||
#include <vtkm/cont/internal/StorageDeprecated.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
@ -256,652 +252,6 @@ struct GetTypeInParentheses<void(T)>
|
||||
#define VTKM_ARRAY_HANDLE_SUBCLASS_NT(classname, superclass) \
|
||||
VTK_M_ARRAY_HANDLE_SUBCLASS_IMPL(classname, (classname), superclass, )
|
||||
|
||||
/// \brief Manages an array-worth of data.
|
||||
///
|
||||
/// \c ArrayHandle manages as array of data that can be manipulated by VTKm
|
||||
/// algorithms. The \c ArrayHandle may have up to two copies of the array, one
|
||||
/// for the control environment and one for the execution environment, although
|
||||
/// depending on the device and how the array is being used, the \c ArrayHandle
|
||||
/// will only have one copy when possible.
|
||||
///
|
||||
/// An ArrayHandle can be constructed one of two ways. Its default construction
|
||||
/// creates an empty, unallocated array that can later be allocated and filled
|
||||
/// either by the user or a VTKm algorithm. The \c ArrayHandle can also be
|
||||
/// constructed with iterators to a user's array. In this case the \c
|
||||
/// ArrayHandle will keep a reference to this array but will throw an exception
|
||||
/// if asked to re-allocate to a larger size.
|
||||
///
|
||||
/// \c ArrayHandle behaves like a shared smart pointer in that when it is copied
|
||||
/// each copy holds a reference to the same array. These copies are reference
|
||||
/// counted so that when all copies of the \c ArrayHandle are destroyed, any
|
||||
/// allocated memory is released.
|
||||
///
|
||||
///
|
||||
template <typename T, typename StorageTag_ = VTKM_DEFAULT_STORAGE_TAG>
|
||||
class VTKM_ALWAYS_EXPORT ArrayHandle : public internal::ArrayHandleBase
|
||||
{
|
||||
private:
|
||||
// Basic storage is specialized; this template should not be instantiated
|
||||
// for it. Specialization is in ArrayHandleBasicImpl.h
|
||||
static_assert(!std::is_same<StorageTag_, StorageTagBasic>::value,
|
||||
"StorageTagBasic should not use this implementation.");
|
||||
|
||||
using ExecutionManagerType =
|
||||
vtkm::cont::internal::ArrayHandleExecutionManagerBase<T, StorageTag_>;
|
||||
|
||||
using MutexType = std::mutex;
|
||||
using LockType = std::unique_lock<MutexType>;
|
||||
|
||||
mutable vtkm::cont::internal::Buffer BufferAsStorageWrapper;
|
||||
|
||||
public:
|
||||
using StorageType = vtkm::cont::internal::Storage<T, StorageTag_>;
|
||||
using ValueType = T;
|
||||
using StorageTag = StorageTag_;
|
||||
using WritePortalType = typename StorageType::PortalType;
|
||||
using ReadPortalType = typename StorageType::PortalConstType;
|
||||
template <typename DeviceAdapterTag>
|
||||
struct ExecutionTypes
|
||||
{
|
||||
using Portal = typename ExecutionManagerType::template ExecutionTypes<DeviceAdapterTag>::Portal;
|
||||
using PortalConst =
|
||||
typename ExecutionManagerType::template ExecutionTypes<DeviceAdapterTag>::PortalConst;
|
||||
};
|
||||
|
||||
using PortalControl VTKM_DEPRECATED(1.6, "Use ArrayHandle::WritePortalType instead.") =
|
||||
typename StorageType::PortalType;
|
||||
using PortalConstControl VTKM_DEPRECATED(1.6, "Use ArrayHandle::ReadPortalType instead.") =
|
||||
typename StorageType::PortalConstType;
|
||||
|
||||
// Handle the fact that the ArrayHandle design has changed.
|
||||
VTKM_STATIC_ASSERT_MSG((std::is_same<typename StorageType::HasOldBridge, std::true_type>::value),
|
||||
"ArrayHandle design has changed. To support old-style arrays, have the "
|
||||
"Storage implementation subclass StorageDeprecated.");
|
||||
VTKM_CONT static constexpr vtkm::IdComponent GetNumberOfBuffers() { return 1; }
|
||||
VTKM_CONT vtkm::cont::internal::Buffer* GetBuffers() const
|
||||
{
|
||||
this->BufferAsStorageWrapper.SetMetaData(*this);
|
||||
return &this->BufferAsStorageWrapper;
|
||||
}
|
||||
|
||||
VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers)
|
||||
{
|
||||
VTKM_ASSERT(buffers[0].MetaDataIsType<ArrayHandle>());
|
||||
*this = buffers[0].GetMetaData<ArrayHandle>();
|
||||
}
|
||||
|
||||
/// Constructs an empty ArrayHandle. Typically used for output or
|
||||
/// intermediate arrays that will be filled by a VTKm algorithm.
|
||||
///
|
||||
VTKM_CONT ArrayHandle();
|
||||
|
||||
/// Copy constructor.
|
||||
///
|
||||
/// Implemented so that it is defined exclusively in the control environment.
|
||||
/// If there is a separate device for the execution environment (for example,
|
||||
/// with CUDA), then the automatically generated copy constructor could be
|
||||
/// created for all devices, and it would not be valid for all devices.
|
||||
///
|
||||
ArrayHandle(const vtkm::cont::ArrayHandle<ValueType, StorageTag>& src);
|
||||
|
||||
/// Move constructor.
|
||||
///
|
||||
/// Implemented so that it is defined exclusively in the control environment.
|
||||
/// If there is a separate device for the execution environment (for example,
|
||||
/// with CUDA), then the automatically generated move constructor could be
|
||||
/// created for all devices, and it would not be valid for all devices.
|
||||
///
|
||||
ArrayHandle(vtkm::cont::ArrayHandle<ValueType, StorageTag>&& src) noexcept;
|
||||
|
||||
/// Special constructor for subclass specializations that need to set the
|
||||
/// initial state of the control array. When this constructor is used, it
|
||||
/// is assumed that the control array is valid.
|
||||
///
|
||||
ArrayHandle(const StorageType& storage);
|
||||
|
||||
|
||||
/// Special constructor for subclass specializations that need to set the
|
||||
/// initial state of the control array. When this constructor is used, it
|
||||
/// is assumed that the control array is valid.
|
||||
///
|
||||
ArrayHandle(StorageType&& storage) noexcept;
|
||||
|
||||
/// Destructs an empty ArrayHandle.
|
||||
///
|
||||
/// Implemented so that it is defined exclusively in the control environment.
|
||||
/// If there is a separate device for the execution environment (for example,
|
||||
/// with CUDA), then the automatically generated destructor could be
|
||||
/// created for all devices, and it would not be valid for all devices.
|
||||
///
|
||||
~ArrayHandle();
|
||||
|
||||
/// \brief Copies an ArrayHandle
|
||||
///
|
||||
VTKM_CONT
|
||||
vtkm::cont::ArrayHandle<ValueType, StorageTag>& operator=(
|
||||
const vtkm::cont::ArrayHandle<ValueType, StorageTag>& src);
|
||||
|
||||
/// \brief Move and Assignment of an ArrayHandle
|
||||
///
|
||||
VTKM_CONT
|
||||
vtkm::cont::ArrayHandle<ValueType, StorageTag>& operator=(
|
||||
vtkm::cont::ArrayHandle<ValueType, StorageTag>&& src) noexcept;
|
||||
|
||||
/// Like a pointer, two \c ArrayHandles are considered equal if they point
|
||||
/// to the same location in memory.
|
||||
///
|
||||
VTKM_CONT
|
||||
bool operator==(const ArrayHandle<ValueType, StorageTag>& rhs) const
|
||||
{
|
||||
return (this->Internals == rhs.Internals);
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
bool operator!=(const ArrayHandle<ValueType, StorageTag>& rhs) const
|
||||
{
|
||||
return (this->Internals != rhs.Internals);
|
||||
}
|
||||
|
||||
template <typename VT, typename ST>
|
||||
VTKM_CONT bool operator==(const ArrayHandle<VT, ST>&) const
|
||||
{
|
||||
return false; // different valuetype and/or storage
|
||||
}
|
||||
|
||||
template <typename VT, typename ST>
|
||||
VTKM_CONT bool operator!=(const ArrayHandle<VT, ST>&) const
|
||||
{
|
||||
return true; // different valuetype and/or storage
|
||||
}
|
||||
|
||||
/// Get the storage.
|
||||
///
|
||||
VTKM_CONT StorageType& GetStorage();
|
||||
|
||||
/// Get the storage.
|
||||
///
|
||||
VTKM_CONT const StorageType& GetStorage() const;
|
||||
|
||||
/// Get the array portal of the control array.
|
||||
/// Since worklet invocations are asynchronous and this routine is a synchronization point,
|
||||
/// exceptions maybe thrown for errors from previously executed worklets.
|
||||
///
|
||||
/// \deprecated Use `WritePortal` instead. Note that the portal returned from `WritePortal`
|
||||
/// will disallow any other reads or writes to the array while it is in scope.
|
||||
///
|
||||
VTKM_CONT
|
||||
VTKM_DEPRECATED(1.6,
|
||||
"Use ArrayHandle::WritePortal() instead. "
|
||||
"Note that the returned portal will lock the array while it is in scope.")
|
||||
|
||||
/// \cond NOPE
|
||||
typename StorageType::PortalType GetPortalControl();
|
||||
/// \endcond
|
||||
|
||||
/// Get the array portal of the control array.
|
||||
/// Since worklet invocations are asynchronous and this routine is a synchronization point,
|
||||
/// exceptions maybe thrown for errors from previously executed worklets.
|
||||
///
|
||||
/// \deprecated Use `ReadPortal` instead. Note that the portal returned from `ReadPortal`
|
||||
/// will disallow any writes to the array while it is in scope.
|
||||
///
|
||||
VTKM_CONT
|
||||
VTKM_DEPRECATED(1.6,
|
||||
"Use ArrayHandle::ReadPortal() instead. "
|
||||
"Note that the returned portal will lock the array while it is in scope.")
|
||||
/// \cond NOPE
|
||||
typename StorageType::PortalConstType GetPortalConstControl() const;
|
||||
/// \endcond
|
||||
|
||||
/// \@{
|
||||
/// \brief Get an array portal that can be used in the control environment.
|
||||
///
|
||||
/// The returned array can be used in the control environment to read values from the array. (It
|
||||
/// is not possible to write to the returned portal. That is `Get` will work on the portal, but
|
||||
/// `Set` will not.)
|
||||
///
|
||||
/// **Note:** The returned portal cannot be used in the execution environment. This is because
|
||||
/// the portal will not work on some devices like GPUs. To get a portal that will work in the
|
||||
/// execution environment, use `PrepareForInput`.
|
||||
///
|
||||
VTKM_CONT ReadPortalType ReadPortal() const;
|
||||
/// \@}
|
||||
|
||||
/// \@{
|
||||
/// \brief Get an array portal that can be used in the control environment.
|
||||
///
|
||||
/// The returned array can be used in the control environment to reand and write values to the
|
||||
/// array.
|
||||
///
|
||||
///
|
||||
/// **Note:** The returned portal cannot be used in the execution environment. This is because
|
||||
/// the portal will not work on some devices like GPUs. To get a portal that will work in the
|
||||
/// execution environment, use `PrepareForInput`.
|
||||
///
|
||||
VTKM_CONT WritePortalType WritePortal() const;
|
||||
/// \@}
|
||||
|
||||
/// Returns the number of entries in the array.
|
||||
///
|
||||
VTKM_CONT vtkm::Id GetNumberOfValues() const
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
|
||||
return this->GetNumberOfValues(lock);
|
||||
}
|
||||
|
||||
/// \brief Allocates an array large enough to hold the given number of values.
|
||||
///
|
||||
/// The allocation may be done on an already existing array, but can wipe out
|
||||
/// any data already in the array. This method can throw
|
||||
/// ErrorBadAllocation if the array cannot be allocated or
|
||||
/// ErrorBadValue if the allocation is not feasible (for example, the
|
||||
/// array storage is read-only).
|
||||
///
|
||||
VTKM_CONT
|
||||
void Allocate(vtkm::Id numberOfValues)
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
this->Allocate(numberOfValues, token);
|
||||
}
|
||||
VTKM_CONT void Allocate(vtkm::Id numberOfValues, vtkm::cont::Token& token)
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
this->WaitToWrite(lock, token);
|
||||
this->ReleaseResourcesExecutionInternal(lock, token);
|
||||
this->Internals->GetControlArray(lock)->Allocate(numberOfValues);
|
||||
// Set to false and then to true to ensure anything pointing to an array before the allocate
|
||||
// is invalidated.
|
||||
this->Internals->SetControlArrayValid(lock, false);
|
||||
this->Internals->SetControlArrayValid(lock, true);
|
||||
}
|
||||
|
||||
/// \brief Reduces the size of the array without changing its values.
|
||||
///
|
||||
/// This method allows you to resize the array without reallocating it. The
|
||||
/// number of entries in the array is changed to \c numberOfValues. The data
|
||||
/// in the array (from indices 0 to \c numberOfValues - 1) are the same, but
|
||||
/// \c numberOfValues must be equal or less than the preexisting size
|
||||
/// (returned from GetNumberOfValues). That is, this method can only be used
|
||||
/// to shorten the array, not lengthen.
|
||||
VTKM_CONT void Shrink(vtkm::Id numberOfValues)
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
this->Shrink(numberOfValues, token);
|
||||
}
|
||||
VTKM_CONT void Shrink(vtkm::Id numberOfValues, vtkm::cont::Token& token);
|
||||
|
||||
/// Releases any resources being used in the execution environment (that are
|
||||
/// not being shared by the control environment).
|
||||
///
|
||||
VTKM_CONT void ReleaseResourcesExecution()
|
||||
{
|
||||
// A Token should not be declared within the scope of a lock. when the token goes out of scope
|
||||
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
|
||||
// the lock.
|
||||
vtkm::cont::Token token;
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
this->WaitToWrite(lock, token);
|
||||
|
||||
// Save any data in the execution environment by making sure it is synced
|
||||
// with the control environment.
|
||||
this->SyncControlArray(lock, token);
|
||||
|
||||
this->ReleaseResourcesExecutionInternal(lock, token);
|
||||
}
|
||||
}
|
||||
|
||||
/// Releases all resources in both the control and execution environments.
|
||||
///
|
||||
VTKM_CONT void ReleaseResources()
|
||||
{
|
||||
// A Token should not be declared within the scope of a lock. when the token goes out of scope
|
||||
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
|
||||
// the lock.
|
||||
vtkm::cont::Token token;
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
|
||||
this->ReleaseResourcesExecutionInternal(lock, token);
|
||||
|
||||
if (this->Internals->IsControlArrayValid(lock))
|
||||
{
|
||||
this->Internals->GetControlArray(lock)->ReleaseResources();
|
||||
this->Internals->SetControlArrayValid(lock, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepares this array to be used as an input to an operation in the
|
||||
/// execution environment. If necessary, copies data to the execution
|
||||
/// environment. Can throw an exception if this array does not yet contain
|
||||
/// any data. Returns a portal that can be used in code running in the
|
||||
/// execution environment.
|
||||
///
|
||||
/// The `Token` object provided will be attached to this `ArrayHandle`.
|
||||
/// The returned portal is guaranteed to be valid while the `Token` is
|
||||
/// still attached and in scope. Other operations on this `ArrayHandle`
|
||||
/// that would invalidate the returned portal will block until the `Token`
|
||||
/// is released. Likewise, this method will block if another `Token` is
|
||||
/// already attached. This can potentially lead to deadlocks.
|
||||
///
|
||||
template <typename DeviceAdapterTag>
|
||||
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::PortalConst PrepareForInput(
|
||||
DeviceAdapterTag,
|
||||
vtkm::cont::Token& token) const;
|
||||
|
||||
/// Prepares (allocates) this array to be used as an output from an operation
|
||||
/// in the execution environment. The internal state of this class is set to
|
||||
/// have valid data in the execution array with the assumption that the array
|
||||
/// will be filled soon (i.e. before any other methods of this object are
|
||||
/// called). Returns a portal that can be used in code running in the
|
||||
/// execution environment.
|
||||
///
|
||||
/// The `Token` object provided will be attached to this `ArrayHandle`.
|
||||
/// The returned portal is guaranteed to be valid while the `Token` is
|
||||
/// still attached and in scope. Other operations on this `ArrayHandle`
|
||||
/// that would invalidate the returned portal will block until the `Token`
|
||||
/// is released. Likewise, this method will block if another `Token` is
|
||||
/// already attached. This can potentially lead to deadlocks.
|
||||
///
|
||||
template <typename DeviceAdapterTag>
|
||||
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::Portal
|
||||
PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag, vtkm::cont::Token& token);
|
||||
|
||||
/// Prepares this array to be used in an in-place operation (both as input
|
||||
/// and output) in the execution environment. If necessary, copies data to
|
||||
/// the execution environment. Can throw an exception if this array does not
|
||||
/// yet contain any data. Returns a portal that can be used in code running
|
||||
/// in the execution environment.
|
||||
///
|
||||
/// The `Token` object provided will be attached to this `ArrayHandle`.
|
||||
/// The returned portal is guaranteed to be valid while the `Token` is
|
||||
/// still attached and in scope. Other operations on this `ArrayHandle`
|
||||
/// that would invalidate the returned portal will block until the `Token`
|
||||
/// is released. Likewise, this method will block if another `Token` is
|
||||
/// already attached. This can potentially lead to deadlocks.
|
||||
///
|
||||
template <typename DeviceAdapterTag>
|
||||
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::Portal PrepareForInPlace(
|
||||
DeviceAdapterTag,
|
||||
vtkm::cont::Token& token);
|
||||
|
||||
template <typename DeviceAdapterTag>
|
||||
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInput now requires a vtkm::cont::Token object.")
|
||||
typename ExecutionTypes<DeviceAdapterTag>::PortalConst PrepareForInput(DeviceAdapterTag) const
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
return this->PrepareForInput(DeviceAdapterTag{}, token);
|
||||
}
|
||||
template <typename DeviceAdapterTag>
|
||||
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForOutput now requires a vtkm::cont::Token object.")
|
||||
typename ExecutionTypes<DeviceAdapterTag>::Portal
|
||||
PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag)
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
return this->PrepareForOutput(numberOfValues, DeviceAdapterTag{}, token);
|
||||
}
|
||||
template <typename DeviceAdapterTag>
|
||||
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInPlace now requires a vtkm::cont::Token object.")
|
||||
typename ExecutionTypes<DeviceAdapterTag>::Portal PrepareForInPlace(DeviceAdapterTag)
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
return this->PrepareForInPlace(DeviceAdapterTag{}, token);
|
||||
}
|
||||
|
||||
/// Returns the DeviceAdapterId for the current device. If there is no device
|
||||
/// with an up-to-date copy of the data, VTKM_DEVICE_ADAPTER_UNDEFINED is
|
||||
/// returned.
|
||||
///
|
||||
/// Note that in a multithreaded environment the validity of this result can
|
||||
/// change.
|
||||
VTKM_CONT
|
||||
DeviceAdapterId GetDeviceAdapterId() const
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
return this->Internals->IsExecutionArrayValid(lock)
|
||||
? this->Internals->GetExecutionArray(lock)->GetDeviceAdapterId()
|
||||
: DeviceAdapterTagUndefined{};
|
||||
}
|
||||
|
||||
/// Synchronizes the control array with the execution array. If either the
|
||||
/// user array or control array is already valid, this method does nothing
|
||||
/// (because the data is already available in the control environment).
|
||||
/// Although the internal state of this class can change, the method is
|
||||
/// declared const because logically the data does not.
|
||||
///
|
||||
VTKM_CONT void SyncControlArray() const
|
||||
{
|
||||
// A Token should not be declared within the scope of a lock. when the token goes out of scope
|
||||
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
|
||||
// the lock.
|
||||
vtkm::cont::Token token;
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
this->SyncControlArray(lock, token);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Enqueue a token for access to this ArrayHandle.
|
||||
///
|
||||
/// This method places the given `Token` into the queue of `Token`s waiting for
|
||||
/// access to this `ArrayHandle` and then returns immediately. When this token
|
||||
/// is later used to get data from this `ArrayHandle` (for example, in a call to
|
||||
/// `PrepareForInput`), it will use this place in the queue while waiting for
|
||||
/// access.
|
||||
///
|
||||
/// This method is to be used to ensure that a set of accesses to an `ArrayHandle`
|
||||
/// that happen on multiple threads occur in a specified order. For example, if
|
||||
/// you spawn of a job to modify data in an `ArrayHandle` and then spawn off a job
|
||||
/// that reads that same data, you need to make sure that the first job gets
|
||||
/// access to the `ArrayHandle` before the second. If they both just attempt to call
|
||||
/// their respective `Prepare` methods, there is no guarantee which order they
|
||||
/// will occur. Having the spawning thread first call this method will ensure the order.
|
||||
///
|
||||
/// \warning After calling this method it is required to subsequently
|
||||
/// call a method like one of the `Prepare` methods that attaches the token
|
||||
/// to this `ArrayHandle`. Otherwise, the enqueued token will block any subsequent
|
||||
/// access to the `ArrayHandle`, even if the `Token` is destroyed.
|
||||
///
|
||||
VTKM_CONT void Enqueue(const vtkm::cont::Token& token) const;
|
||||
|
||||
private:
|
||||
/// Acquires a lock on the internals of this `ArrayHandle`. The calling
|
||||
/// function should keep the returned lock and let it go out of scope
|
||||
/// when the lock is no longer needed.
|
||||
///
|
||||
LockType GetLock() const { return LockType(this->Internals->Mutex); }
|
||||
|
||||
/// Returns true if read operations can currently be performed.
|
||||
///
|
||||
VTKM_CONT bool CanRead(const LockType& lock, const vtkm::cont::Token& token) const;
|
||||
|
||||
//// Returns true if write operations can currently be performed.
|
||||
///
|
||||
VTKM_CONT bool CanWrite(const LockType& lock, const vtkm::cont::Token& token) const;
|
||||
|
||||
//// Will block the current thread until a read can be performed.
|
||||
///
|
||||
VTKM_CONT void WaitToRead(LockType& lock, vtkm::cont::Token& token) const;
|
||||
|
||||
//// Will block the current thread until a write can be performed.
|
||||
///
|
||||
VTKM_CONT void WaitToWrite(LockType& lock, vtkm::cont::Token& token, bool fakeRead = false) const;
|
||||
|
||||
/// Gets this array handle ready to interact with the given device. If the
|
||||
/// array handle has already interacted with this device, then this method
|
||||
/// does nothing. Although the internal state of this class can change, the
|
||||
/// method is declared const because logically the data does not.
|
||||
///
|
||||
template <typename DeviceAdapterTag>
|
||||
VTKM_CONT void PrepareForDevice(LockType& lock, vtkm::cont::Token& token, DeviceAdapterTag) const;
|
||||
|
||||
/// Synchronizes the control array with the execution array. If either the
|
||||
/// user array or control array is already valid, this method does nothing
|
||||
/// (because the data is already available in the control environment).
|
||||
/// Although the internal state of this class can change, the method is
|
||||
/// declared const because logically the data does not.
|
||||
///
|
||||
VTKM_CONT void SyncControlArray(LockType& lock, vtkm::cont::Token& token) const;
|
||||
|
||||
vtkm::Id GetNumberOfValues(LockType& lock) const;
|
||||
|
||||
VTKM_CONT
|
||||
void ReleaseResourcesExecutionInternal(LockType& lock, vtkm::cont::Token& token) const
|
||||
{
|
||||
if (this->Internals->IsExecutionArrayValid(lock))
|
||||
{
|
||||
this->WaitToWrite(lock, token);
|
||||
// Note that it is possible that while waiting someone else deleted the execution array.
|
||||
// That is why we check again.
|
||||
}
|
||||
if (this->Internals->IsExecutionArrayValid(lock))
|
||||
{
|
||||
this->Internals->GetExecutionArray(lock)->ReleaseResources();
|
||||
this->Internals->SetExecutionArrayValid(lock, false);
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_CONT void Enqueue(const LockType& lock, const vtkm::cont::Token& token) const;
|
||||
|
||||
class VTKM_ALWAYS_EXPORT InternalStruct
|
||||
{
|
||||
mutable StorageType ControlArray;
|
||||
mutable std::shared_ptr<bool> ControlArrayValid;
|
||||
|
||||
mutable std::unique_ptr<ExecutionManagerType> ExecutionArray;
|
||||
mutable bool ExecutionArrayValid = false;
|
||||
|
||||
mutable vtkm::cont::Token::ReferenceCount ReadCount = 0;
|
||||
mutable vtkm::cont::Token::ReferenceCount WriteCount = 0;
|
||||
|
||||
mutable std::deque<vtkm::cont::Token::Reference> Queue;
|
||||
|
||||
VTKM_CONT void CheckLock(const LockType& lock) const
|
||||
{
|
||||
VTKM_ASSERT((lock.mutex() == &this->Mutex) && (lock.owns_lock()));
|
||||
}
|
||||
|
||||
public:
|
||||
MutexType Mutex;
|
||||
std::condition_variable ConditionVariable;
|
||||
|
||||
InternalStruct() = default;
|
||||
InternalStruct(const StorageType& storage);
|
||||
InternalStruct(StorageType&& storage);
|
||||
|
||||
~InternalStruct()
|
||||
{
|
||||
// It should not be possible to destroy this array if any tokens are still attached to it.
|
||||
LockType lock(this->Mutex);
|
||||
VTKM_ASSERT((*this->GetReadCount(lock) == 0) && (*this->GetWriteCount(lock) == 0));
|
||||
this->SetControlArrayValid(lock, false);
|
||||
}
|
||||
|
||||
// To access any feature in InternalStruct, you must have locked the mutex. You have
|
||||
// to prove it by passing in a reference to a std::unique_lock.
|
||||
VTKM_CONT bool IsControlArrayValid(const LockType& lock) const
|
||||
{
|
||||
this->CheckLock(lock);
|
||||
if (!this->ControlArrayValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return *this->ControlArrayValid;
|
||||
}
|
||||
}
|
||||
VTKM_CONT void SetControlArrayValid(const LockType& lock, bool value)
|
||||
{
|
||||
this->CheckLock(lock);
|
||||
if (IsControlArrayValid(lock) == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (value) // ControlArrayValid == false or nullptr
|
||||
{
|
||||
// If we are changing the valid flag from false to true, then refresh the pointer.
|
||||
// There may be array portals that already have a reference to the flag. Those portals
|
||||
// will stay in an invalid state whereas new portals will go to a valid state. To
|
||||
// handle both conditions, drop the old reference and create a new one.
|
||||
this->ControlArrayValid.reset(new bool(true));
|
||||
}
|
||||
else // value == false and ControlArrayValid == true
|
||||
{
|
||||
*this->ControlArrayValid = false;
|
||||
}
|
||||
}
|
||||
VTKM_CONT std::shared_ptr<bool> GetControlArrayValidPointer(const LockType& lock) const
|
||||
{
|
||||
this->CheckLock(lock);
|
||||
return this->ControlArrayValid;
|
||||
}
|
||||
VTKM_CONT StorageType* GetControlArray(const LockType& lock) const
|
||||
{
|
||||
this->CheckLock(lock);
|
||||
return &this->ControlArray;
|
||||
}
|
||||
|
||||
VTKM_CONT bool IsExecutionArrayValid(const LockType& lock) const
|
||||
{
|
||||
this->CheckLock(lock);
|
||||
return this->ExecutionArrayValid;
|
||||
}
|
||||
VTKM_CONT void SetExecutionArrayValid(const LockType& lock, bool value)
|
||||
{
|
||||
this->CheckLock(lock);
|
||||
this->ExecutionArrayValid = value;
|
||||
}
|
||||
VTKM_CONT ExecutionManagerType* GetExecutionArray(const LockType& lock) const
|
||||
{
|
||||
this->CheckLock(lock);
|
||||
return this->ExecutionArray.get();
|
||||
}
|
||||
VTKM_CONT void DeleteExecutionArray(const LockType& lock)
|
||||
{
|
||||
this->CheckLock(lock);
|
||||
this->ExecutionArray.reset();
|
||||
this->ExecutionArrayValid = false;
|
||||
}
|
||||
template <typename DeviceAdapterTag>
|
||||
VTKM_CONT void NewExecutionArray(const LockType& lock, DeviceAdapterTag)
|
||||
{
|
||||
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
|
||||
this->CheckLock(lock);
|
||||
VTKM_ASSERT(this->ExecutionArray == nullptr);
|
||||
VTKM_ASSERT(!this->ExecutionArrayValid);
|
||||
this->ExecutionArray.reset(
|
||||
new vtkm::cont::internal::ArrayHandleExecutionManager<T, StorageTag, DeviceAdapterTag>(
|
||||
&this->ControlArray));
|
||||
}
|
||||
VTKM_CONT vtkm::cont::Token::ReferenceCount* GetReadCount(const LockType& lock) const
|
||||
{
|
||||
this->CheckLock(lock);
|
||||
return &this->ReadCount;
|
||||
}
|
||||
VTKM_CONT vtkm::cont::Token::ReferenceCount* GetWriteCount(const LockType& lock) const
|
||||
{
|
||||
this->CheckLock(lock);
|
||||
return &this->WriteCount;
|
||||
}
|
||||
VTKM_CONT std::deque<vtkm::cont::Token::Reference>& GetQueue(const LockType& lock) const
|
||||
{
|
||||
this->CheckLock(lock);
|
||||
return this->Queue;
|
||||
}
|
||||
};
|
||||
|
||||
VTKM_CONT
|
||||
ArrayHandle(const std::shared_ptr<InternalStruct>& i)
|
||||
: Internals(i)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<InternalStruct> Internals;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
@ -917,91 +267,31 @@ VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::DeviceAdapterId ArrayHandleGetDeviceAdapt
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// This macro is used to declare an ArrayHandle that uses the new style of Storage
|
||||
// that leverages Buffer objects. This macro will go away once ArrayHandle
|
||||
// is replaced with ArrayHandleNewStyle. To use this macro, first have a declaration
|
||||
// of the template and then put the macro like this:
|
||||
//
|
||||
// template <typename T>
|
||||
// VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagFoo);
|
||||
//
|
||||
// Don't forget to use VTKM_PASS_COMMAS if one of the macro arguments contains
|
||||
// a template with multiple parameters.
|
||||
#define VTKM_ARRAY_HANDLE_NEW_STYLE(ValueType_, StorageType_) \
|
||||
class VTKM_ALWAYS_EXPORT ArrayHandle<ValueType_, StorageType_> \
|
||||
: public ArrayHandleNewStyle<ValueType_, StorageType_> \
|
||||
{ \
|
||||
using Superclass = ArrayHandleNewStyle<ValueType_, StorageType_>; \
|
||||
\
|
||||
public: \
|
||||
VTKM_CONT \
|
||||
ArrayHandle() \
|
||||
: Superclass() \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
VTKM_CONT \
|
||||
ArrayHandle(const ArrayHandle<ValueType_, StorageType_>& src) \
|
||||
: Superclass(src) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
VTKM_CONT \
|
||||
ArrayHandle(ArrayHandle<ValueType_, StorageType_>&& src) noexcept \
|
||||
: Superclass(std::move(src)) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
VTKM_CONT \
|
||||
ArrayHandle(const ArrayHandleNewStyle<ValueType_, StorageType_>& src) \
|
||||
: Superclass(src) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
VTKM_CONT \
|
||||
ArrayHandle(ArrayHandleNewStyle<ValueType_, StorageType_>&& src) noexcept \
|
||||
: Superclass(std::move(src)) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers) \
|
||||
: Superclass(buffers) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
VTKM_CONT ArrayHandle(const std::vector<vtkm::cont::internal::Buffer>& buffers) \
|
||||
: Superclass(buffers) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
VTKM_CONT ArrayHandle(std::vector<vtkm::cont::internal::Buffer>&& buffers) \
|
||||
: Superclass(std::move(buffers)) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
VTKM_CONT \
|
||||
ArrayHandle<ValueType_, StorageType_>& operator=( \
|
||||
const ArrayHandle<ValueType_, StorageType_>& src) \
|
||||
{ \
|
||||
this->Superclass::operator=(src); \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
VTKM_CONT \
|
||||
ArrayHandle<ValueType_, StorageType_>& operator=( \
|
||||
ArrayHandle<ValueType_, StorageType_>&& src) noexcept \
|
||||
{ \
|
||||
this->Superclass::operator=(std::move(src)); \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
VTKM_CONT ~ArrayHandle() {} \
|
||||
}
|
||||
|
||||
/// This new style of ArrayHandle will eventually replace the classic ArrayHandle
|
||||
/// \brief Manages an array-worth of data.
|
||||
///
|
||||
/// `ArrayHandle` manages as array of data that can be manipulated by VTKm
|
||||
/// algorithms. The `ArrayHandle` may have up to two copies of the array, one
|
||||
/// for the control environment and one for the execution environment, although
|
||||
/// depending on the device and how the array is being used, the `ArrayHandle`
|
||||
/// will only have one copy when possible.
|
||||
///
|
||||
/// An `ArrayHandle` is often constructed by instantiating one of the `ArrayHandle`
|
||||
/// subclasses. Several basic `ArrayHandle` types can also be constructed directly
|
||||
/// and then allocated. The `ArrayHandleBasic` subclass provides mechanisms for
|
||||
/// importing user arrays into an `ArrayHandle`.
|
||||
///
|
||||
/// `ArrayHandle` behaves like a shared smart pointer in that when it is copied
|
||||
/// each copy holds a reference to the same array. These copies are reference
|
||||
/// counted so that when all copies of the `ArrayHandle` are destroyed, any
|
||||
/// allocated memory is released.
|
||||
///
|
||||
template <typename T, typename StorageTag_ = VTKM_DEFAULT_STORAGE_TAG>
|
||||
class VTKM_ALWAYS_EXPORT ArrayHandleNewStyle : public internal::ArrayHandleBase
|
||||
class VTKM_ALWAYS_EXPORT ArrayHandle : public internal::ArrayHandleBase
|
||||
{
|
||||
VTKM_STATIC_ASSERT_MSG(
|
||||
(internal::IsValidArrayHandle<T, StorageTag_>::value),
|
||||
"Attempted to create an ArrayHandle with an invalid type/storage combination.");
|
||||
|
||||
public:
|
||||
using ValueType = T;
|
||||
using StorageTag = StorageTag_;
|
||||
@ -1025,7 +315,7 @@ public:
|
||||
|
||||
/// Constructs an empty ArrayHandle.
|
||||
///
|
||||
VTKM_CONT ArrayHandleNewStyle()
|
||||
VTKM_CONT ArrayHandle()
|
||||
: Buffers(static_cast<std::size_t>(StorageType::GetNumberOfBuffers()))
|
||||
{
|
||||
}
|
||||
@ -1037,7 +327,7 @@ public:
|
||||
/// with CUDA), then the automatically generated copy constructor could be
|
||||
/// created for all devices, and it would not be valid for all devices.
|
||||
///
|
||||
VTKM_CONT ArrayHandleNewStyle(const vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& src)
|
||||
VTKM_CONT ArrayHandle(const vtkm::cont::ArrayHandle<ValueType, StorageTag>& src)
|
||||
: Buffers(src.Buffers)
|
||||
{
|
||||
}
|
||||
@ -1049,8 +339,7 @@ public:
|
||||
/// with CUDA), then the automatically generated move constructor could be
|
||||
/// created for all devices, and it would not be valid for all devices.
|
||||
///
|
||||
VTKM_CONT ArrayHandleNewStyle(
|
||||
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>&& src) noexcept
|
||||
VTKM_CONT ArrayHandle(vtkm::cont::ArrayHandle<ValueType, StorageTag>&& src) noexcept
|
||||
: Buffers(std::move(src.Buffers))
|
||||
{
|
||||
}
|
||||
@ -1059,19 +348,19 @@ public:
|
||||
/// Special constructor for subclass specializations that need to set the
|
||||
/// initial state array. Used when pulling data from other sources.
|
||||
///
|
||||
VTKM_CONT ArrayHandleNewStyle(const std::vector<vtkm::cont::internal::Buffer>& buffers)
|
||||
VTKM_CONT ArrayHandle(const std::vector<vtkm::cont::internal::Buffer>& buffers)
|
||||
: Buffers(buffers)
|
||||
{
|
||||
VTKM_ASSERT(static_cast<vtkm::IdComponent>(this->Buffers.size()) == this->GetNumberOfBuffers());
|
||||
}
|
||||
|
||||
VTKM_CONT ArrayHandleNewStyle(std::vector<vtkm::cont::internal::Buffer>&& buffers) noexcept
|
||||
VTKM_CONT ArrayHandle(std::vector<vtkm::cont::internal::Buffer>&& buffers) noexcept
|
||||
: Buffers(std::move(buffers))
|
||||
{
|
||||
VTKM_ASSERT(static_cast<vtkm::IdComponent>(this->Buffers.size()) == this->GetNumberOfBuffers());
|
||||
}
|
||||
|
||||
VTKM_CONT ArrayHandleNewStyle(const vtkm::cont::internal::Buffer* buffers)
|
||||
VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers)
|
||||
: Buffers(buffers, buffers + StorageType::GetNumberOfBuffers())
|
||||
{
|
||||
}
|
||||
@ -1084,13 +373,13 @@ public:
|
||||
/// with CUDA), then the automatically generated destructor could be
|
||||
/// created for all devices, and it would not be valid for all devices.
|
||||
///
|
||||
VTKM_CONT ~ArrayHandleNewStyle() {}
|
||||
VTKM_CONT ~ArrayHandle() {}
|
||||
|
||||
/// \brief Copies an ArrayHandle
|
||||
///
|
||||
VTKM_CONT
|
||||
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& operator=(
|
||||
const vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& src)
|
||||
vtkm::cont::ArrayHandle<ValueType, StorageTag>& operator=(
|
||||
const vtkm::cont::ArrayHandle<ValueType, StorageTag>& src)
|
||||
{
|
||||
this->Buffers = src.Buffers;
|
||||
return *this;
|
||||
@ -1099,8 +388,8 @@ public:
|
||||
/// \brief Move and Assignment of an ArrayHandle
|
||||
///
|
||||
VTKM_CONT
|
||||
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& operator=(
|
||||
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>&& src) noexcept
|
||||
vtkm::cont::ArrayHandle<ValueType, StorageTag>& operator=(
|
||||
vtkm::cont::ArrayHandle<ValueType, StorageTag>&& src) noexcept
|
||||
{
|
||||
this->Buffers = std::move(src.Buffers);
|
||||
return *this;
|
||||
@ -1411,8 +700,7 @@ public:
|
||||
///
|
||||
/// Takes the data that is in \a source and copies that data into this array.
|
||||
///
|
||||
VTKM_CONT void DeepCopyFrom(
|
||||
const vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& source) const
|
||||
VTKM_CONT void DeepCopyFrom(const vtkm::cont::ArrayHandle<ValueType, StorageTag>& source) const
|
||||
{
|
||||
VTKM_ASSERT(this->Buffers.size() == source.Buffers.size());
|
||||
|
||||
@ -1667,8 +955,4 @@ VTKM_CONT inline std::vector<vtkm::cont::internal::Buffer> CreateBuffers(const A
|
||||
#include <vtkm/cont/ArrayHandleBasic.h>
|
||||
#endif
|
||||
|
||||
#ifndef vtk_m_cont_ArrayHandle_hxx
|
||||
#include <vtkm/cont/ArrayHandle.hxx>
|
||||
#endif
|
||||
|
||||
#endif //vtk_m_cont_ArrayHandle_h
|
||||
|
@ -1,596 +0,0 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_cont_ArrayHandle_hxx
|
||||
#define vtk_m_cont_ArrayHandle_hxx
|
||||
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
template <typename T, typename S>
|
||||
ArrayHandle<T, S>::InternalStruct::InternalStruct(
|
||||
const typename ArrayHandle<T, S>::StorageType& storage)
|
||||
: ControlArray(storage)
|
||||
, ControlArrayValid(new bool(true))
|
||||
, ExecutionArrayValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
ArrayHandle<T, S>::InternalStruct::InternalStruct(typename ArrayHandle<T, S>::StorageType&& storage)
|
||||
: ControlArray(std::move(storage))
|
||||
, ControlArrayValid(new bool(true))
|
||||
, ExecutionArrayValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
ArrayHandle<T, S>::ArrayHandle()
|
||||
: Internals(std::make_shared<InternalStruct>())
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
ArrayHandle<T, S>::ArrayHandle(const ArrayHandle<T, S>& src)
|
||||
: Internals(src.Internals)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
ArrayHandle<T, S>::ArrayHandle(ArrayHandle<T, S>&& src) noexcept
|
||||
: Internals(std::move(src.Internals))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
ArrayHandle<T, S>::ArrayHandle(const typename ArrayHandle<T, S>::StorageType& storage)
|
||||
: Internals(std::make_shared<InternalStruct>(storage))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
ArrayHandle<T, S>::ArrayHandle(typename ArrayHandle<T, S>::StorageType&& storage) noexcept
|
||||
: Internals(std::make_shared<InternalStruct>(std::move(storage)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
ArrayHandle<T, S>::~ArrayHandle()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
ArrayHandle<T, S>& ArrayHandle<T, S>::operator=(const ArrayHandle<T, S>& src)
|
||||
{
|
||||
this->Internals = src.Internals;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
ArrayHandle<T, S>& ArrayHandle<T, S>::operator=(ArrayHandle<T, S>&& src) noexcept
|
||||
{
|
||||
this->Internals = std::move(src.Internals);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
typename ArrayHandle<T, S>::StorageType& ArrayHandle<T, S>::GetStorage()
|
||||
{
|
||||
// A Token should not be declared within the scope of a lock. when the token goes out of scope
|
||||
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
|
||||
// the lock.
|
||||
vtkm::cont::Token token;
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
|
||||
this->SyncControlArray(lock, token);
|
||||
if (this->Internals->IsControlArrayValid(lock))
|
||||
{
|
||||
return *this->Internals->GetControlArray(lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw vtkm::cont::ErrorInternal(
|
||||
"ArrayHandle::SyncControlArray did not make control array valid.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
const typename ArrayHandle<T, S>::StorageType& ArrayHandle<T, S>::GetStorage() const
|
||||
{
|
||||
// A Token should not be declared within the scope of a lock. when the token goes out of scope
|
||||
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
|
||||
// the lock.
|
||||
vtkm::cont::Token token;
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
|
||||
this->SyncControlArray(lock, token);
|
||||
if (this->Internals->IsControlArrayValid(lock))
|
||||
{
|
||||
return *this->Internals->GetControlArray(lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw vtkm::cont::ErrorInternal(
|
||||
"ArrayHandle::SyncControlArray did not make control array valid.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
typename ArrayHandle<T, S>::StorageType::PortalType ArrayHandle<T, S>::GetPortalControl()
|
||||
{
|
||||
// A Token should not be declared within the scope of a lock. when the token goes out of scope
|
||||
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
|
||||
// the lock.
|
||||
vtkm::cont::Token token;
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
|
||||
this->SyncControlArray(lock, token);
|
||||
if (this->Internals->IsControlArrayValid(lock))
|
||||
{
|
||||
// If the user writes into the iterator we return, then the execution
|
||||
// array will become invalid. Play it safe and release the execution
|
||||
// resources. (Use the const version to preserve the execution array.)
|
||||
this->ReleaseResourcesExecutionInternal(lock, token);
|
||||
return this->Internals->GetControlArray(lock)->GetPortal();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw vtkm::cont::ErrorInternal(
|
||||
"ArrayHandle::SyncControlArray did not make control array valid.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
typename ArrayHandle<T, S>::StorageType::PortalConstType ArrayHandle<T, S>::GetPortalConstControl()
|
||||
const
|
||||
{
|
||||
// A Token should not be declared within the scope of a lock. when the token goes out of scope
|
||||
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
|
||||
// the lock.
|
||||
vtkm::cont::Token token;
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
|
||||
this->SyncControlArray(lock, token);
|
||||
if (this->Internals->IsControlArrayValid(lock))
|
||||
{
|
||||
return this->Internals->GetControlArray(lock)->GetPortalConst();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw vtkm::cont::ErrorInternal(
|
||||
"ArrayHandle::SyncControlArray did not make control array valid.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
typename ArrayHandle<T, S>::ReadPortalType ArrayHandle<T, S>::ReadPortal() const
|
||||
{
|
||||
// A Token should not be declared within the scope of a lock. when the token goes out of scope
|
||||
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
|
||||
// the lock.
|
||||
vtkm::cont::Token token;
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
this->WaitToRead(lock, token);
|
||||
|
||||
this->SyncControlArray(lock, token);
|
||||
if (this->Internals->IsControlArrayValid(lock))
|
||||
{
|
||||
return ReadPortalType(this->Internals->GetControlArray(lock)->GetPortalConst());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw vtkm::cont::ErrorInternal(
|
||||
"ArrayHandle::SyncControlArray did not make control array valid.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
typename ArrayHandle<T, S>::WritePortalType ArrayHandle<T, S>::WritePortal() const
|
||||
{
|
||||
// A Token should not be declared within the scope of a lock. when the token goes out of scope
|
||||
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
|
||||
// the lock.
|
||||
vtkm::cont::Token token;
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
this->WaitToWrite(lock, token);
|
||||
|
||||
this->SyncControlArray(lock, token);
|
||||
if (this->Internals->IsControlArrayValid(lock))
|
||||
{
|
||||
// If the user writes into the iterator we return, then the execution
|
||||
// array will become invalid. Play it safe and release the execution
|
||||
// resources. (Use the const version to preserve the execution array.)
|
||||
this->ReleaseResourcesExecutionInternal(lock, token);
|
||||
return WritePortalType(this->Internals->GetControlArray(lock)->GetPortal());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw vtkm::cont::ErrorInternal(
|
||||
"ArrayHandle::SyncControlArray did not make control array valid.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
vtkm::Id ArrayHandle<T, S>::GetNumberOfValues(LockType& lock) const
|
||||
{
|
||||
if (this->Internals->IsControlArrayValid(lock))
|
||||
{
|
||||
return this->Internals->GetControlArray(lock)->GetNumberOfValues();
|
||||
}
|
||||
else if (this->Internals->IsExecutionArrayValid(lock))
|
||||
{
|
||||
return this->Internals->GetExecutionArray(lock)->GetNumberOfValues();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void ArrayHandle<T, S>::Shrink(vtkm::Id numberOfValues, vtkm::cont::Token& token)
|
||||
{
|
||||
VTKM_ASSERT(numberOfValues >= 0);
|
||||
|
||||
if (numberOfValues > 0)
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
|
||||
vtkm::Id originalNumberOfValues = this->GetNumberOfValues(lock);
|
||||
|
||||
if (numberOfValues < originalNumberOfValues)
|
||||
{
|
||||
this->WaitToWrite(lock, token);
|
||||
if (this->Internals->IsControlArrayValid(lock))
|
||||
{
|
||||
this->Internals->GetControlArray(lock)->Shrink(numberOfValues);
|
||||
}
|
||||
if (this->Internals->IsExecutionArrayValid(lock))
|
||||
{
|
||||
this->Internals->GetExecutionArray(lock)->Shrink(numberOfValues);
|
||||
}
|
||||
}
|
||||
else if (numberOfValues == originalNumberOfValues)
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
else // numberOfValues > originalNumberOfValues
|
||||
{
|
||||
throw vtkm::cont::ErrorBadValue("ArrayHandle::Shrink cannot be used to grow array.");
|
||||
}
|
||||
|
||||
VTKM_ASSERT(this->GetNumberOfValues(lock) == numberOfValues);
|
||||
}
|
||||
else // numberOfValues == 0
|
||||
{
|
||||
// If we are shrinking to 0, there is nothing to save and we might as well
|
||||
// free up memory. Plus, some storage classes expect that data will be
|
||||
// deallocated when the size goes to zero.
|
||||
this->Allocate(0, token);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
template <typename DeviceAdapterTag>
|
||||
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::PortalConst
|
||||
ArrayHandle<T, S>::PrepareForInput(DeviceAdapterTag device, vtkm::cont::Token& token) const
|
||||
{
|
||||
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
|
||||
|
||||
LockType lock = this->GetLock();
|
||||
this->WaitToRead(lock, token);
|
||||
|
||||
if (!this->Internals->IsControlArrayValid(lock) && !this->Internals->IsExecutionArrayValid(lock))
|
||||
{
|
||||
// Want to use an empty array.
|
||||
// Set up ArrayHandle state so this actually works.
|
||||
this->Internals->GetControlArray(lock)->Allocate(0);
|
||||
this->Internals->SetControlArrayValid(lock, true);
|
||||
}
|
||||
|
||||
this->PrepareForDevice(lock, token, device);
|
||||
auto portal = this->Internals->GetExecutionArray(lock)->PrepareForInput(
|
||||
!this->Internals->IsExecutionArrayValid(lock), device, token);
|
||||
|
||||
this->Internals->SetExecutionArrayValid(lock, true);
|
||||
|
||||
return portal;
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
template <typename DeviceAdapterTag>
|
||||
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::Portal
|
||||
ArrayHandle<T, S>::PrepareForOutput(vtkm::Id numberOfValues,
|
||||
DeviceAdapterTag device,
|
||||
vtkm::cont::Token& token)
|
||||
{
|
||||
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
|
||||
|
||||
LockType lock = this->GetLock();
|
||||
this->WaitToWrite(lock, token);
|
||||
|
||||
// Invalidate any control arrays.
|
||||
// Should the control array resource be released? Probably not a good
|
||||
// idea when shared with execution.
|
||||
this->Internals->SetControlArrayValid(lock, false);
|
||||
|
||||
this->PrepareForDevice(lock, token, device);
|
||||
auto portal =
|
||||
this->Internals->GetExecutionArray(lock)->PrepareForOutput(numberOfValues, device, token);
|
||||
|
||||
// We are assuming that the calling code will fill the array using the
|
||||
// iterators we are returning, so go ahead and mark the execution array as
|
||||
// having valid data. (A previous version of this class had a separate call
|
||||
// to mark the array as filled, but that was onerous to call at the the
|
||||
// right time and rather pointless since it is basically always the case
|
||||
// that the array is going to be filled before anything else. In this
|
||||
// implementation the only access to the array is through the iterators
|
||||
// returned from this method, so you would have to work to invalidate this
|
||||
// assumption anyway.)
|
||||
this->Internals->SetExecutionArrayValid(lock, true);
|
||||
|
||||
return portal;
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
template <typename DeviceAdapterTag>
|
||||
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::Portal
|
||||
ArrayHandle<T, S>::PrepareForInPlace(DeviceAdapterTag device, vtkm::cont::Token& token)
|
||||
{
|
||||
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
|
||||
|
||||
LockType lock = this->GetLock();
|
||||
this->WaitToWrite(lock, token);
|
||||
|
||||
if (!this->Internals->IsControlArrayValid(lock) && !this->Internals->IsExecutionArrayValid(lock))
|
||||
{
|
||||
// Want to use an empty array.
|
||||
// Set up ArrayHandle state so this actually works.
|
||||
this->Internals->GetControlArray(lock)->Allocate(0);
|
||||
this->Internals->SetControlArrayValid(lock, true);
|
||||
}
|
||||
|
||||
this->PrepareForDevice(lock, token, device);
|
||||
auto portal = this->Internals->GetExecutionArray(lock)->PrepareForInPlace(
|
||||
!this->Internals->IsExecutionArrayValid(lock), device, token);
|
||||
|
||||
this->Internals->SetExecutionArrayValid(lock, true);
|
||||
|
||||
// Invalidate any control arrays since their data will become invalid when
|
||||
// the execution data is overwritten. Don't actually release the control
|
||||
// array. It may be shared as the execution array.
|
||||
this->Internals->SetControlArrayValid(lock, false);
|
||||
|
||||
return portal;
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
template <typename DeviceAdapterTag>
|
||||
void ArrayHandle<T, S>::PrepareForDevice(LockType& lock,
|
||||
vtkm::cont::Token& token,
|
||||
DeviceAdapterTag device) const
|
||||
{
|
||||
if (this->Internals->GetExecutionArray(lock) != nullptr)
|
||||
{
|
||||
if (this->Internals->GetExecutionArray(lock)->IsDeviceAdapter(DeviceAdapterTag()))
|
||||
{
|
||||
// Already have manager for correct device adapter. Nothing to do.
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Have the wrong manager. Delete the old one and create a new one
|
||||
// of the right type. (TODO: it would be possible for the array handle
|
||||
// to hold references to execution arrays on multiple devices. When data
|
||||
// are written on one devices, all the other devices should get cleared.)
|
||||
|
||||
// BUG: There is a non-zero chance that while waiting for the write lock, another thread
|
||||
// could change the ExecutionInterface, which would cause problems. In the future we should
|
||||
// support multiple devices, in which case we would not have to delete one execution array
|
||||
// to load another.
|
||||
// BUG: The current implementation does not allow the ArrayHandle to be on two devices
|
||||
// at the same time. Thus, it is not possible for two simultaneously read from the same
|
||||
// ArrayHandle on two different devices. This might cause unexpected deadlocks.
|
||||
this->WaitToWrite(lock, token, true); // Make sure no one is reading device array
|
||||
this->SyncControlArray(lock, token);
|
||||
// Need to change some state that does not change the logical state from
|
||||
// an external point of view.
|
||||
this->Internals->DeleteExecutionArray(lock);
|
||||
}
|
||||
}
|
||||
|
||||
// Need to change some state that does not change the logical state from
|
||||
// an external point of view.
|
||||
this->Internals->NewExecutionArray(lock, device);
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void ArrayHandle<T, S>::SyncControlArray(LockType& lock, vtkm::cont::Token& token) const
|
||||
{
|
||||
if (!this->Internals->IsControlArrayValid(lock))
|
||||
{
|
||||
// It may be the case that `SyncControlArray` is called from a method that has a `Token`.
|
||||
// However, if we are here, that `Token` should not already be attached to this array.
|
||||
// If it were, then there should be no reason to move data arround (unless the `Token`
|
||||
// was used when preparing for multiple devices, which it should not be used like that).
|
||||
this->WaitToRead(lock, token);
|
||||
|
||||
// Need to change some state that does not change the logical state from
|
||||
// an external point of view.
|
||||
if (this->Internals->IsExecutionArrayValid(lock))
|
||||
{
|
||||
this->Internals->GetExecutionArray(lock)->RetrieveOutputData(
|
||||
this->Internals->GetControlArray(lock));
|
||||
this->Internals->SetControlArrayValid(lock, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This array is in the null state (there is nothing allocated), but
|
||||
// the calling function wants to do something with the array. Put this
|
||||
// class into a valid state by allocating an array of size 0.
|
||||
this->Internals->GetControlArray(lock)->Allocate(0);
|
||||
this->Internals->SetControlArrayValid(lock, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
bool ArrayHandle<T, S>::CanRead(const LockType& lock, const vtkm::cont::Token& token) const
|
||||
{
|
||||
// If the token is already attached to this array, then we allow reading.
|
||||
if (token.IsAttached(this->Internals->GetWriteCount(lock)) ||
|
||||
token.IsAttached(this->Internals->GetReadCount(lock)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there is anyone else waiting at the top of the queue, we cannot access this array.
|
||||
auto& queue = this->Internals->GetQueue(lock);
|
||||
if (!queue.empty() && (queue.front() != token))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// No one else is waiting, so we can read the array as long as no one else is writing.
|
||||
return (*this->Internals->GetWriteCount(lock) < 1);
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
bool ArrayHandle<T, S>::CanWrite(const LockType& lock, const vtkm::cont::Token& token) const
|
||||
{
|
||||
// If the token is already attached to this array, then we allow writing.
|
||||
if (token.IsAttached(this->Internals->GetWriteCount(lock)) ||
|
||||
token.IsAttached(this->Internals->GetReadCount(lock)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there is anyone else waiting at the top of the queue, we cannot access this array.
|
||||
auto& queue = this->Internals->GetQueue(lock);
|
||||
if (!queue.empty() && (queue.front() != token))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// No one else is waiting, so we can write the array as long as no one else is reading or writing.
|
||||
return ((*this->Internals->GetWriteCount(lock) < 1) &&
|
||||
(*this->Internals->GetReadCount(lock) < 1));
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void ArrayHandle<T, S>::WaitToRead(LockType& lock, vtkm::cont::Token& token) const
|
||||
{
|
||||
this->Enqueue(lock, token);
|
||||
|
||||
// Note that if you deadlocked here, that means that you are trying to do a read operation on an
|
||||
// array where an object is writing to it.
|
||||
this->Internals->ConditionVariable.wait(
|
||||
lock, [&lock, &token, this] { return this->CanRead(lock, token); });
|
||||
|
||||
token.Attach(this->Internals,
|
||||
this->Internals->GetReadCount(lock),
|
||||
lock,
|
||||
&this->Internals->ConditionVariable);
|
||||
|
||||
// We successfully attached the token. Pop it off the queue.
|
||||
auto& queue = this->Internals->GetQueue(lock);
|
||||
if (!queue.empty() && queue.front() == token)
|
||||
{
|
||||
queue.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void ArrayHandle<T, S>::WaitToWrite(LockType& lock, vtkm::cont::Token& token, bool fakeRead) const
|
||||
{
|
||||
this->Enqueue(lock, token);
|
||||
|
||||
// Note that if you deadlocked here, that means that you are trying to do a write operation on an
|
||||
// array where an object is reading or writing to it.
|
||||
this->Internals->ConditionVariable.wait(
|
||||
lock, [&lock, &token, this] { return this->CanWrite(lock, token); });
|
||||
|
||||
if (!fakeRead)
|
||||
{
|
||||
token.Attach(this->Internals,
|
||||
this->Internals->GetWriteCount(lock),
|
||||
lock,
|
||||
&this->Internals->ConditionVariable);
|
||||
}
|
||||
else
|
||||
{
|
||||
// A current feature limitation of ArrayHandle is that it can only exist on one device at
|
||||
// a time. Thus, if a read request comes in for a different device, the prepare has to
|
||||
// get satisfy a write lock to boot the array off the existing device. However, we don't
|
||||
// want to attach the Token as a write lock because the resulting state is for reading only
|
||||
// and others might also want to read. So, we have to pretend that this is a read lock even
|
||||
// though we have to make a change to the array.
|
||||
//
|
||||
// The main point is, this condition is a hack that should go away once ArrayHandle supports
|
||||
// multiple devices at once.
|
||||
token.Attach(this->Internals,
|
||||
this->Internals->GetReadCount(lock),
|
||||
lock,
|
||||
&this->Internals->ConditionVariable);
|
||||
}
|
||||
|
||||
// We successfully attached the token. Pop it off the queue.
|
||||
auto& queue = this->Internals->GetQueue(lock);
|
||||
if (!queue.empty() && queue.front() == token)
|
||||
{
|
||||
queue.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void ArrayHandle<T, S>::Enqueue(const vtkm::cont::Token& token) const
|
||||
{
|
||||
LockType lock = this->GetLock();
|
||||
this->Enqueue(lock, token);
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void ArrayHandle<T, S>::Enqueue(const LockType& lock, const vtkm::cont::Token& token) const
|
||||
{
|
||||
if (token.IsAttached(this->Internals->GetWriteCount(lock)) ||
|
||||
token.IsAttached(this->Internals->GetReadCount(lock)))
|
||||
{
|
||||
// Do not need to enqueue if we are already attached.
|
||||
return;
|
||||
}
|
||||
|
||||
auto& queue = this->Internals->GetQueue(lock);
|
||||
if (std::find(queue.begin(), queue.end(), token.GetReference()) != queue.end())
|
||||
{
|
||||
// This token is already in the queue.
|
||||
return;
|
||||
}
|
||||
|
||||
this->Internals->GetQueue(lock).push_back(token.GetReference());
|
||||
}
|
||||
}
|
||||
} // vtkm::cont
|
||||
|
||||
#endif //vtk_m_cont_ArrayHandle_hxx
|
@ -41,11 +41,11 @@ VTKM_STORAGE_INSTANTIATE(vtkm::Float64)
|
||||
|
||||
} // namespace internal
|
||||
|
||||
#define VTKM_ARRAYHANDLE_INSTANTIATE(Type) \
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<Type, StorageTagBasic>; \
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Vec<Type, 2>, StorageTagBasic>; \
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Vec<Type, 3>, StorageTagBasic>; \
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Vec<Type, 4>, StorageTagBasic>;
|
||||
#define VTKM_ARRAYHANDLE_INSTANTIATE(Type) \
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<Type, StorageTagBasic>; \
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 2>, StorageTagBasic>; \
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 3>, StorageTagBasic>; \
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 4>, StorageTagBasic>;
|
||||
|
||||
VTKM_ARRAYHANDLE_INSTANTIATE(char)
|
||||
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Int8)
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define vtk_m_cont_ArrayHandleBasic_h
|
||||
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayPortalToIterators.h>
|
||||
#include <vtkm/cont/SerializableTypeString.h>
|
||||
#include <vtkm/cont/Serialization.h>
|
||||
#include <vtkm/cont/Storage.h>
|
||||
@ -70,9 +71,6 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagBasic);
|
||||
|
||||
template <typename T>
|
||||
class VTKM_ALWAYS_EXPORT ArrayHandleBasic : public ArrayHandle<T, vtkm::cont::StorageTagBasic>
|
||||
{
|
||||
@ -383,14 +381,13 @@ VTKM_STORAGE_EXPORT(vtkm::Float64)
|
||||
|
||||
} // namespace internal
|
||||
|
||||
#define VTKM_ARRAYHANDLE_EXPORT(Type) \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<Type, StorageTagBasic>; \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT \
|
||||
ArrayHandleNewStyle<vtkm::Vec<Type, 2>, StorageTagBasic>; \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT \
|
||||
ArrayHandleNewStyle<vtkm::Vec<Type, 3>, StorageTagBasic>; \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT \
|
||||
ArrayHandleNewStyle<vtkm::Vec<Type, 4>, StorageTagBasic>;
|
||||
#define VTKM_ARRAYHANDLE_EXPORT(Type) \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<Type, StorageTagBasic>; \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT \
|
||||
ArrayHandle<vtkm::Vec<Type, 2>, StorageTagBasic>; \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT \
|
||||
ArrayHandle<vtkm::Vec<Type, 3>, StorageTagBasic>; \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 4>, StorageTagBasic>;
|
||||
|
||||
VTKM_ARRAYHANDLE_EXPORT(char)
|
||||
VTKM_ARRAYHANDLE_EXPORT(vtkm::Int8)
|
||||
|
@ -136,9 +136,6 @@ public:
|
||||
} // end namespace internal
|
||||
|
||||
|
||||
template <typename T>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::internal::StorageTagBitField);
|
||||
|
||||
/// The ArrayHandleBitField class is a boolean-valued ArrayHandle that is backed
|
||||
/// by a BitField.
|
||||
///
|
||||
|
@ -284,11 +284,6 @@ public:
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
template <typename T, typename ST1, typename ST2, typename ST3>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(
|
||||
T,
|
||||
VTKM_PASS_COMMAS(vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>));
|
||||
|
||||
/// ArrayHandleCartesianProduct is a specialization of ArrayHandle. It takes two delegate
|
||||
/// array handle and makes a new handle that access the corresponding entries
|
||||
/// in these arrays as a pair.
|
||||
|
@ -131,9 +131,6 @@ struct Storage<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceStorage_>>
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T1, typename T2, typename S>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T1, VTKM_PASS_COMMAS(vtkm::cont::StorageTagCast<T2, S>));
|
||||
|
||||
/// \brief Cast the values of an array to the specified type, on demand.
|
||||
///
|
||||
/// ArrayHandleCast is a specialization of ArrayHandleTransform. Given an ArrayHandle
|
||||
|
@ -402,9 +402,6 @@ struct Storage<T, vtkm::cont::StorageTagCompositeVec<StorageTag>> : Storage<T, S
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T, typename... Ss>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagCompositeVec<Ss...>);
|
||||
|
||||
/// \brief An \c ArrayHandle that combines components from other arrays.
|
||||
///
|
||||
/// \c ArrayHandleCompositeVector is a specialization of \c ArrayHandle that
|
||||
|
@ -245,9 +245,6 @@ namespace vtkm
|
||||
namespace cont
|
||||
{
|
||||
|
||||
template <typename T, typename S1, typename S2>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(StorageTagConcatenate<S1, S2>));
|
||||
|
||||
template <typename ArrayHandleType1, typename ArrayHandleType2>
|
||||
class ArrayHandleConcatenate
|
||||
: public vtkm::cont::ArrayHandle<typename ArrayHandleType1::ValueType,
|
||||
|
@ -51,9 +51,6 @@ struct Storage<T, vtkm::cont::StorageTagConstant> : Storage<T, StorageTagConstan
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagConstant);
|
||||
|
||||
/// \brief An array handle with a constant value.
|
||||
///
|
||||
/// ArrayHandleConstant is an implicit array handle with a constant value. A
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <vtkm/cont/ArrayHandleImplicit.h>
|
||||
|
||||
#include <vtkm/TypeTraits.h>
|
||||
#include <vtkm/VecTraits.h>
|
||||
|
||||
namespace vtkm
|
||||
@ -72,20 +73,53 @@ private:
|
||||
vtkm::Id NumberOfValues;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename T, typename UseVecTraits = vtkm::HasVecTraits<T>>
|
||||
struct CanCountImpl;
|
||||
|
||||
template <typename T>
|
||||
struct CanCountImpl<T, std::false_type>
|
||||
{
|
||||
using TTraits = vtkm::TypeTraits<T>;
|
||||
static constexpr bool IsNumeric =
|
||||
!std::is_same<typename TTraits::NumericTag, vtkm::TypeTraitsUnknownTag>::value;
|
||||
|
||||
static constexpr bool value = IsNumeric;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CanCountImpl<T, std::true_type>
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
using BaseType = typename VTraits::BaseComponentType;
|
||||
static constexpr bool IsBool = std::is_same<BaseType, bool>::value;
|
||||
|
||||
static constexpr bool value = CanCountImpl<BaseType, std::false_type>::value && !IsBool;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Not all types can be counted.
|
||||
template <typename T>
|
||||
struct CanCount
|
||||
{
|
||||
static constexpr bool value = detail::CanCountImpl<T>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using StorageTagCountingSuperclass =
|
||||
vtkm::cont::StorageTagImplicit<internal::ArrayPortalCounting<T>>;
|
||||
|
||||
template <typename T>
|
||||
struct Storage<T, vtkm::cont::StorageTagCounting> : Storage<T, StorageTagCountingSuperclass<T>>
|
||||
struct Storage<T, typename std::enable_if<CanCount<T>::value, vtkm::cont::StorageTagCounting>::type>
|
||||
: Storage<T, StorageTagCountingSuperclass<T>>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagCounting);
|
||||
|
||||
/// ArrayHandleCounting is a specialization of ArrayHandle. By default it
|
||||
/// contains a increment value, that is increment for each step between zero
|
||||
/// and the passed in length
|
||||
|
@ -590,11 +590,6 @@ struct DecoratorHandleTraits
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T, typename DecoratorImplT, typename... ArrayTs>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(
|
||||
T,
|
||||
VTKM_PASS_COMMAS(internal::StorageTagDecorator<DecoratorImplT, ArrayTs...>));
|
||||
|
||||
/// \brief A fancy ArrayHandle that can be used to modify the results from one
|
||||
/// or more source ArrayHandle.
|
||||
///
|
||||
|
@ -144,10 +144,6 @@ struct ArrayHandleDiscardTraits
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
// This can go away once ArrayHandle is replaced with ArrayHandleNewStyle
|
||||
template <typename T>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::internal::StorageTagDiscard);
|
||||
|
||||
/// ArrayHandleDiscard is a write-only array that discards all data written to
|
||||
/// it. This can be used to save memory when a filter provides optional outputs
|
||||
/// that are not needed.
|
||||
|
@ -170,9 +170,6 @@ namespace vtkm
|
||||
namespace cont
|
||||
{
|
||||
|
||||
template <typename T, typename ArrayT>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagExtractComponent<ArrayT>);
|
||||
|
||||
/// \brief A fancy ArrayHandle that turns a vector array into a scalar array by
|
||||
/// slicing out a single component of each vector.
|
||||
///
|
||||
|
@ -14,11 +14,17 @@
|
||||
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
|
||||
#include <vtkm/cont/internal/ArrayHandleDeprecated.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
VTKM_ARRAY_HANDLE_DEPRECATED(VTKM_PASS_COMMAS(vtkm::Vec<T, 3>),
|
||||
vtkm::cont::internal::StorageTagExtrude);
|
||||
|
||||
template <typename T>
|
||||
class VTKM_ALWAYS_EXPORT ArrayHandleExtrudeCoords
|
||||
: public vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, internal::StorageTagExtrude>
|
||||
|
@ -13,11 +13,16 @@
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/StorageExtrude.h>
|
||||
|
||||
#include <vtkm/cont/internal/ArrayHandleDeprecated.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
VTKM_ARRAY_HANDLE_DEPRECATED(T, vtkm::cont::internal::StorageTagExtrude);
|
||||
|
||||
template <typename T>
|
||||
class VTKM_ALWAYS_EXPORT ArrayHandleExtrudeField
|
||||
: public vtkm::cont::ArrayHandle<T, internal::StorageTagExtrude>
|
||||
|
@ -174,9 +174,6 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T, vtkm::IdComponent N, typename S>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(vtkm::cont::StorageTagGroupVec<S, N>));
|
||||
|
||||
/// \brief Fancy array handle that groups values into vectors.
|
||||
///
|
||||
/// It is sometimes the case that an array is stored such that consecutive
|
||||
|
@ -22,8 +22,6 @@
|
||||
#include <vtkm/Assert.h>
|
||||
#include <vtkm/VecFromPortal.h>
|
||||
|
||||
#include <vtkm/exec/arg/FetchTagArrayDirectOut.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace internal
|
||||
@ -104,49 +102,8 @@ private:
|
||||
OffsetsPortalType OffsetsPortal;
|
||||
};
|
||||
|
||||
} // namespace internal (in vtkm)
|
||||
|
||||
namespace exec
|
||||
{
|
||||
namespace arg
|
||||
{
|
||||
|
||||
// We need to override the fetch for output fields using
|
||||
// ArrayPortalGroupVecVariable because this portal does not behave like most
|
||||
// ArrayPortals. Usually you ignore the Load and implement the Store. But if
|
||||
// you ignore the Load, the VecFromPortal gets no portal to set values into.
|
||||
// Instead, you need to implement the Load to point to the array portal. You
|
||||
// can also ignore the Store because the data is already set in the array at
|
||||
// that point.
|
||||
template <typename ComponentsPortalType, typename OffsetsPortalType>
|
||||
struct Fetch<vtkm::exec::arg::FetchTagArrayDirectOut,
|
||||
vtkm::exec::arg::AspectTagDefault,
|
||||
vtkm::internal::ArrayPortalGroupVecVariable<ComponentsPortalType, OffsetsPortalType>>
|
||||
{
|
||||
using ExecObjectType =
|
||||
vtkm::internal::ArrayPortalGroupVecVariable<ComponentsPortalType, OffsetsPortalType>;
|
||||
using ValueType = typename ExecObjectType::ValueType;
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
template <typename ThreadIndicesType>
|
||||
VTKM_EXEC ValueType Load(const ThreadIndicesType& indices,
|
||||
const ExecObjectType& arrayPortal) const
|
||||
{
|
||||
return arrayPortal.Get(indices.GetOutputIndex());
|
||||
}
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
template <typename ThreadIndicesType>
|
||||
VTKM_EXEC void Store(const ThreadIndicesType&, const ExecObjectType&, const ValueType&) const
|
||||
{
|
||||
// We can actually ignore this because the VecFromPortal will already have
|
||||
// set new values in the array.
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::exec::arg
|
||||
} // namespace vtkm::internal
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
@ -254,9 +211,6 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T, typename S1, typename S2>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(vtkm::cont::StorageTagGroupVecVariable<S1, S2>));
|
||||
|
||||
/// \brief Fancy array handle that groups values into vectors of different sizes.
|
||||
///
|
||||
/// It is sometimes the case that you need to run a worklet with an input or
|
||||
@ -423,6 +377,10 @@ VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Id> ConvertNumComponentsToOffsets(
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
||||
//=============================================================================
|
||||
// Specializations of worklet arguments using ArrayHandleGropuVecVariable
|
||||
#include <vtkm/exec/arg/FetchTagArrayDirectOutArrayHandleGroupVecVariable.h>
|
||||
|
||||
//=============================================================================
|
||||
// Specializations of serialization related classes
|
||||
/// @cond SERIALIZATION
|
||||
|
@ -160,11 +160,6 @@ struct ArrayHandleImplicitTraits
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// This can go away once ArrayHandle is replaced with ArrayHandleNewStyle
|
||||
template <typename PortalType>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(typename PortalType::ValueType,
|
||||
vtkm::cont::StorageTagImplicit<PortalType>);
|
||||
|
||||
/// \brief An \c ArrayHandle that computes values on the fly.
|
||||
///
|
||||
/// \c ArrayHandleImplicit is a specialization of ArrayHandle.
|
||||
|
@ -45,9 +45,6 @@ struct Storage<vtkm::Id, vtkm::cont::StorageTagIndex> : Storage<vtkm::Id, Storag
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(vtkm::Id, vtkm::cont::StorageTagIndex);
|
||||
|
||||
/// \brief An implicit array handle containing the its own indices.
|
||||
///
|
||||
/// \c ArrayHandleIndex is an implicit array handle containing the values
|
||||
|
@ -353,9 +353,6 @@ struct ArrayHandleMultiplexerTraits
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename... Ss>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagMultiplexer<Ss...>);
|
||||
|
||||
/// \brief An ArrayHandle that can behave like several other handles.
|
||||
///
|
||||
/// An \c ArrayHandleMultiplexer simply redirects its calls to another \c ArrayHandle. However
|
||||
|
@ -172,9 +172,6 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T, typename IS, typename VS>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(vtkm::cont::StorageTagPermutation<IS, VS>));
|
||||
|
||||
/// \brief Implicitly permutes the values in an array.
|
||||
///
|
||||
/// ArrayHandlePermutation is a specialization of ArrayHandle. It takes two
|
||||
|
614
vtkm/cont/ArrayHandleRecombineVec.h
Normal file
614
vtkm/cont/ArrayHandleRecombineVec.h
Normal file
@ -0,0 +1,614 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_cont_ArrayHandleRecombineVec_h
|
||||
#define vtk_m_cont_ArrayHandleRecombineVec_h
|
||||
|
||||
#include <vtkm/cont/ArrayExtractComponent.h>
|
||||
#include <vtkm/cont/ArrayHandleMultiplexer.h>
|
||||
#include <vtkm/cont/ArrayHandleStride.h>
|
||||
#include <vtkm/cont/DeviceAdapterTag.h>
|
||||
|
||||
#include <vtkm/VecVariable.h>
|
||||
|
||||
#include <vtkm/internal/ArrayPortalValueReference.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename PortalType>
|
||||
class RecombineVec
|
||||
{
|
||||
vtkm::VecCConst<PortalType> Portals;
|
||||
vtkm::Id Index;
|
||||
|
||||
public:
|
||||
using ComponentType = typename std::remove_const<typename PortalType::ValueType>::type;
|
||||
|
||||
RecombineVec(const RecombineVec&) = default;
|
||||
|
||||
VTKM_EXEC_CONT RecombineVec(const vtkm::VecCConst<PortalType>& portals, vtkm::Id index)
|
||||
: Portals(portals)
|
||||
, Index(index)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT vtkm::IdComponent GetNumberOfComponents() const
|
||||
{
|
||||
return this->Portals.GetNumberOfComponents();
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
vtkm::internal::ArrayPortalValueReference<PortalType> operator[](vtkm::IdComponent cIndex) const
|
||||
{
|
||||
return vtkm::internal::ArrayPortalValueReference<PortalType>(this->Portals[cIndex],
|
||||
this->Index);
|
||||
}
|
||||
|
||||
template <typename T, vtkm::IdComponent DestSize>
|
||||
VTKM_EXEC_CONT void CopyInto(vtkm::Vec<T, DestSize>& dest) const
|
||||
{
|
||||
vtkm::IdComponent numComponents = vtkm::Min(DestSize, this->GetNumberOfComponents());
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
|
||||
{
|
||||
dest[cIndex] = this->Portals[cIndex].Get(this->Index);
|
||||
}
|
||||
// Clear out any components not held by this dynamic Vec-like
|
||||
for (vtkm::IdComponent cIndex = numComponents; cIndex < DestSize; ++cIndex)
|
||||
{
|
||||
dest[cIndex] = vtkm::TypeTraits<T>::ZeroInitialization();
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT vtkm::Id GetIndex() const { return this->Index; }
|
||||
|
||||
VTKM_EXEC_CONT RecombineVec& operator=(const RecombineVec& src)
|
||||
{
|
||||
this->DoCopy(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT RecombineVec& operator=(const T& src)
|
||||
{
|
||||
this->DoCopy(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT operator ComponentType() const { return this->Portals[0].Get(this->Index); }
|
||||
|
||||
template <vtkm::IdComponent N>
|
||||
VTKM_EXEC_CONT operator vtkm::Vec<ComponentType, N>() const
|
||||
{
|
||||
vtkm::Vec<ComponentType, N> result;
|
||||
this->CopyInto(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT RecombineVec& operator+=(const T& src)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
(*this)[cIndex] += VTraits::GetComponent(src, cIndex);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT RecombineVec& operator-=(const T& src)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
(*this)[cIndex] -= VTraits::GetComponent(src, cIndex);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT RecombineVec& operator*=(const T& src)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
(*this)[cIndex] *= VTraits::GetComponent(src, cIndex);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT RecombineVec& operator/=(const T& src)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
(*this)[cIndex] /= VTraits::GetComponent(src, cIndex);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT RecombineVec& operator%=(const T& src)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
(*this)[cIndex] %= VTraits::GetComponent(src, cIndex);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT RecombineVec& operator&=(const T& src)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
(*this)[cIndex] &= VTraits::GetComponent(src, cIndex);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT RecombineVec& operator|=(const T& src)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
(*this)[cIndex] |= VTraits::GetComponent(src, cIndex);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT RecombineVec& operator^=(const T& src)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
(*this)[cIndex] ^= VTraits::GetComponent(src, cIndex);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT RecombineVec& operator>>=(const T& src)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
(*this)[cIndex] >>= VTraits::GetComponent(src, cIndex);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT RecombineVec& operator<<=(const T& src)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
(*this)[cIndex] <<= VTraits::GetComponent(src, cIndex);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
VTKM_EXEC_CONT void DoCopy(const T& src)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
vtkm::IdComponent numComponents = VTraits::GetNumberOfComponents(src);
|
||||
if (numComponents > 1)
|
||||
{
|
||||
if (numComponents > this->GetNumberOfComponents())
|
||||
{
|
||||
numComponents = this->GetNumberOfComponents();
|
||||
}
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
|
||||
{
|
||||
this->Portals[cIndex].Set(this->Index, VTraits::GetComponent(src, cIndex));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Special case when copying from a scalar
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
this->Portals[cIndex].Set(this->Index, VTraits::GetComponent(src, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename PortalType>
|
||||
struct TypeTraits<vtkm::internal::RecombineVec<PortalType>>
|
||||
{
|
||||
private:
|
||||
using VecType = vtkm::internal::RecombineVec<PortalType>;
|
||||
using ComponentType = typename VecType::ComponentType;
|
||||
|
||||
public:
|
||||
using NumericTag = typename vtkm::TypeTraits<ComponentType>::NumericTag;
|
||||
using DimensionalityTag = vtkm::TypeTraitsVectorTag;
|
||||
|
||||
VTKM_EXEC_CONT static vtkm::internal::RecombineVec<PortalType> ZeroInitialization()
|
||||
{
|
||||
// Return a vec-like of size 0.
|
||||
return vtkm::internal::RecombineVec<PortalType>{};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename PortalType>
|
||||
struct VecTraits<vtkm::internal::RecombineVec<PortalType>>
|
||||
{
|
||||
using VecType = vtkm::internal::RecombineVec<PortalType>;
|
||||
using ComponentType = typename VecType::ComponentType;
|
||||
using BaseComponentType = typename vtkm::VecTraits<ComponentType>::BaseComponentType;
|
||||
using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents;
|
||||
using IsSizeStatic = vtkm::VecTraitsTagSizeVariable;
|
||||
|
||||
VTKM_EXEC_CONT static vtkm::IdComponent GetNumberOfComponents(const VecType& vector)
|
||||
{
|
||||
return vector.GetNumberOfComponents();
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
static ComponentType GetComponent(const VecType& vector, vtkm::IdComponent componentIndex)
|
||||
{
|
||||
return vector[componentIndex];
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT static void SetComponent(const VecType& vector,
|
||||
vtkm::IdComponent componentIndex,
|
||||
const ComponentType& component)
|
||||
{
|
||||
vector[componentIndex] = component;
|
||||
}
|
||||
|
||||
template <vtkm::IdComponent destSize>
|
||||
VTKM_EXEC_CONT static void CopyInto(const VecType& src, vtkm::Vec<ComponentType, destSize>& dest)
|
||||
{
|
||||
src.CopyInto(dest);
|
||||
}
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename SourcePortalType>
|
||||
class ArrayPortalRecombineVec
|
||||
{
|
||||
vtkm::VecCConst<SourcePortalType> Portals;
|
||||
|
||||
public:
|
||||
using ValueType = vtkm::internal::RecombineVec<SourcePortalType>;
|
||||
|
||||
ArrayPortalRecombineVec() = default;
|
||||
ArrayPortalRecombineVec(const vtkm::VecCConst<SourcePortalType>& portals)
|
||||
: Portals(portals)
|
||||
{
|
||||
}
|
||||
ArrayPortalRecombineVec(const SourcePortalType* portals, vtkm::IdComponent numComponents)
|
||||
: Portals(portals, numComponents)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return this->Portals[0].GetNumberOfValues(); }
|
||||
|
||||
VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const { return ValueType(this->Portals, index); }
|
||||
|
||||
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
|
||||
{
|
||||
// The ValueType is actually a reference back to the portals, and sets to it should
|
||||
// already be set in the portal. Thus, we don't really need to do anything.
|
||||
VTKM_ASSERT(value.GetIndex() == index);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
VTKM_EXEC_CONT void Set(vtkm::Id index, const T& value) const
|
||||
{
|
||||
using Traits = vtkm::VecTraits<T>;
|
||||
VTKM_ASSERT(Traits::GetNumberOfComponents(value) == this->Portals.GetNumberOfComponents());
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < this->Portals.GetNumberOfComponents(); ++cIndex)
|
||||
{
|
||||
this->Portals[cIndex].Set(index, Traits::GetComponent(value, cIndex));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace vtkm::internal
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
struct StorageTagRecombineVec
|
||||
{
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// Note: Normally a decorating ArrayHandle holds the buffers of the arrays it is decorating
|
||||
// in its list of arrays. However, the numbers of buffers is expected to be compile-time static
|
||||
// and ArrayHandleRecombineVec needs to set the number of buffers at runtime. We cheat around
|
||||
// this by stuffing the decorated buffers in the metadata. To make sure deep copies work
|
||||
// right, a copy of the metadata results in a deep copy of the contained buffers. The
|
||||
// vtkm::cont::internal::Buffer holding the metadata is not supposed to copy the metadata
|
||||
// except for a deep copy (and when it is first set). If this behavior changes, there could
|
||||
// be a performance degredation.
|
||||
struct RecombineVecMetaData
|
||||
{
|
||||
mutable std::vector<vtkm::cont::internal::Buffer> PortalBuffers;
|
||||
std::vector<std::vector<vtkm::cont::internal::Buffer>> ArrayBuffers;
|
||||
|
||||
RecombineVecMetaData() = default;
|
||||
|
||||
RecombineVecMetaData(const RecombineVecMetaData& src) { *this = src; }
|
||||
|
||||
RecombineVecMetaData& operator=(const RecombineVecMetaData& src)
|
||||
{
|
||||
this->ArrayBuffers.resize(src.ArrayBuffers.size());
|
||||
for (std::size_t arrayIndex = 0; arrayIndex < src.ArrayBuffers.size(); ++arrayIndex)
|
||||
{
|
||||
this->ArrayBuffers[arrayIndex].resize(src.ArrayBuffers[arrayIndex].size());
|
||||
for (std::size_t bufferIndex = 0; bufferIndex < src.ArrayBuffers[arrayIndex].size();
|
||||
++bufferIndex)
|
||||
{
|
||||
this->ArrayBuffers[arrayIndex][bufferIndex].DeepCopyFrom(
|
||||
src.ArrayBuffers[arrayIndex][bufferIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
this->PortalBuffers.clear();
|
||||
// Intentionally not copying portals. Portals will be recreated from proper array when requsted.
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using RecombinedPortalType = vtkm::internal::ArrayPortalMultiplexer<
|
||||
typename vtkm::cont::internal::Storage<T, vtkm::cont::StorageTagStride>::ReadPortalType,
|
||||
typename vtkm::cont::internal::Storage<T, vtkm::cont::StorageTagStride>::WritePortalType>;
|
||||
|
||||
template <typename T>
|
||||
using RecombinedValueType = vtkm::internal::RecombineVec<RecombinedPortalType<T>>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename ReadWritePortal>
|
||||
class Storage<vtkm::internal::RecombineVec<ReadWritePortal>,
|
||||
vtkm::cont::internal::StorageTagRecombineVec>
|
||||
{
|
||||
using ComponentType = typename ReadWritePortal::ValueType;
|
||||
using SourceStorage = vtkm::cont::internal::Storage<ComponentType, vtkm::cont::StorageTagStride>;
|
||||
using ArrayType = vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagStride>;
|
||||
|
||||
VTKM_STATIC_ASSERT(
|
||||
(std::is_same<ReadWritePortal, detail::RecombinedPortalType<ComponentType>>::value));
|
||||
|
||||
template <typename Buff>
|
||||
VTKM_CONT static Buff* BuffersForComponent(Buff* buffers, vtkm::IdComponent componentIndex)
|
||||
{
|
||||
return buffers[0]
|
||||
.template GetMetaData<detail::RecombineVecMetaData>()
|
||||
.ArrayBuffers[componentIndex]
|
||||
.data();
|
||||
}
|
||||
|
||||
public:
|
||||
VTKM_STORAGE_NO_RESIZE;
|
||||
|
||||
using ReadPortalType = vtkm::internal::ArrayPortalRecombineVec<ReadWritePortal>;
|
||||
using WritePortalType = vtkm::internal::ArrayPortalRecombineVec<ReadWritePortal>;
|
||||
|
||||
VTKM_CONT static vtkm::IdComponent NumberOfComponents(const vtkm::cont::internal::Buffer* buffers)
|
||||
{
|
||||
return static_cast<vtkm::IdComponent>(
|
||||
buffers[0].GetMetaData<detail::RecombineVecMetaData>().ArrayBuffers.size());
|
||||
}
|
||||
|
||||
VTKM_CONT static vtkm::IdComponent GetNumberOfBuffers() { return 1; }
|
||||
|
||||
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
|
||||
{
|
||||
return SourceStorage::GetNumberOfValues(BuffersForComponent(buffers, 0));
|
||||
}
|
||||
|
||||
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
|
||||
vtkm::cont::DeviceAdapterId device,
|
||||
vtkm::cont::Token& token)
|
||||
{
|
||||
ReadPortalType portal;
|
||||
vtkm::IdComponent numComponents = NumberOfComponents(buffers);
|
||||
|
||||
// The array portal needs a runtime-allocated array of portals for each component.
|
||||
// We use the vtkm::cont::internal::Buffer object to allow us to allocate memory on the
|
||||
// device and copy data there.
|
||||
vtkm::cont::internal::Buffer portalBuffer;
|
||||
portalBuffer.SetNumberOfBytes(static_cast<vtkm::BufferSizeType>(sizeof(ReadWritePortal)) *
|
||||
numComponents,
|
||||
vtkm::CopyFlag::Off,
|
||||
token);
|
||||
|
||||
// Save a reference of the portal in our metadata.
|
||||
// Note that the buffer we create is going to hang around until the ArrayHandle gets
|
||||
// destroyed. The buffers are small and should not be a problem unless you create a
|
||||
// lot of portals.
|
||||
buffers[0].GetMetaData<detail::RecombineVecMetaData>().PortalBuffers.push_back(portalBuffer);
|
||||
|
||||
// Get the control-side memory and fill it with the execution-side portals
|
||||
ReadWritePortal* portals =
|
||||
reinterpret_cast<ReadWritePortal*>(portalBuffer.WritePointerHost(token));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
|
||||
{
|
||||
portals[cIndex] = ReadWritePortal(
|
||||
SourceStorage::CreateReadPortal(BuffersForComponent(buffers, cIndex), device, token));
|
||||
}
|
||||
|
||||
// Now get the execution-side memory (portals will be copied as necessary) and create
|
||||
// the portal for the appropriate device
|
||||
return ReadPortalType(
|
||||
reinterpret_cast<const ReadWritePortal*>(portalBuffer.ReadPointerDevice(device, token)),
|
||||
numComponents);
|
||||
}
|
||||
|
||||
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
|
||||
vtkm::cont::DeviceAdapterId device,
|
||||
vtkm::cont::Token& token)
|
||||
{
|
||||
WritePortalType portal;
|
||||
vtkm::IdComponent numComponents = NumberOfComponents(buffers);
|
||||
|
||||
// The array portal needs a runtime-allocated array of portals for each component.
|
||||
// We use the vtkm::cont::internal::Buffer object to allow us to allocate memory on the
|
||||
// device and copy data there.
|
||||
vtkm::cont::internal::Buffer portalBuffer;
|
||||
portalBuffer.SetNumberOfBytes(static_cast<vtkm::BufferSizeType>(sizeof(ReadWritePortal)) *
|
||||
numComponents,
|
||||
vtkm::CopyFlag::Off,
|
||||
token);
|
||||
|
||||
// Save a reference of the portal in our metadata.
|
||||
// Note that the buffer we create is going to hang around until the ArrayHandle gets
|
||||
// destroyed. The buffers are small and should not be a problem unless you create a
|
||||
// lot of portals.
|
||||
buffers[0].GetMetaData<detail::RecombineVecMetaData>().PortalBuffers.push_back(portalBuffer);
|
||||
|
||||
// Get the control-side memory and fill it with the execution-side portals
|
||||
ReadWritePortal* portals =
|
||||
reinterpret_cast<ReadWritePortal*>(portalBuffer.WritePointerHost(token));
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
|
||||
{
|
||||
portals[cIndex] = ReadWritePortal(
|
||||
SourceStorage::CreateWritePortal(BuffersForComponent(buffers, cIndex), device, token));
|
||||
}
|
||||
|
||||
// Now get the execution-side memory (portals will be copied as necessary) and create
|
||||
// the portal for the appropriate device
|
||||
return WritePortalType(
|
||||
reinterpret_cast<const ReadWritePortal*>(portalBuffer.ReadPointerDevice(device, token)),
|
||||
numComponents);
|
||||
}
|
||||
|
||||
VTKM_CONT static ArrayType ArrayForComponent(const vtkm::cont::internal::Buffer* buffers,
|
||||
vtkm::IdComponent componentIndex)
|
||||
{
|
||||
return ArrayType(BuffersForComponent(buffers, componentIndex));
|
||||
}
|
||||
|
||||
VTKM_CONT static void AppendComponent(vtkm::cont::internal::Buffer* buffers,
|
||||
const ArrayType& array)
|
||||
{
|
||||
std::vector<vtkm::cont::internal::Buffer> arrayBuffers(
|
||||
array.GetBuffers(), array.GetBuffers() + SourceStorage::GetNumberOfBuffers());
|
||||
buffers[0].GetMetaData<detail::RecombineVecMetaData>().ArrayBuffers.push_back(
|
||||
std::move(arrayBuffers));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// \brief A grouping of `ArrayHandleStride`s into an `ArrayHandle` of `Vec`s.
|
||||
///
|
||||
/// The main intention of `ArrayHandleStride` is to pull out a component of an
|
||||
/// `ArrayHandle` without knowing there `ArrayHandle`'s storage or `Vec` shape.
|
||||
/// However, usually you want to do an operation on all the components together.
|
||||
/// `ArrayHandleRecombineVec` implements the functionality to easily take a
|
||||
/// group of extracted components and treat them as a single `ArrayHandle` of
|
||||
/// `Vec` values.
|
||||
///
|
||||
/// Note that caution should be used with `ArrayHandleRecombineVec` because the
|
||||
/// size of the `Vec` values is not known at compile time. Thus, the value
|
||||
/// type of this array is forced to a `VecVariable`, which can cause surprises
|
||||
/// if treated as a `Vec`. In particular, the static `NUM_COMPONENTS` expression
|
||||
/// does not exist.
|
||||
///
|
||||
template <typename ComponentType>
|
||||
class ArrayHandleRecombineVec
|
||||
: public vtkm::cont::ArrayHandle<internal::detail::RecombinedValueType<ComponentType>,
|
||||
vtkm::cont::internal::StorageTagRecombineVec>
|
||||
{
|
||||
public:
|
||||
VTKM_ARRAY_HANDLE_SUBCLASS(
|
||||
ArrayHandleRecombineVec,
|
||||
(ArrayHandleRecombineVec<ComponentType>),
|
||||
(vtkm::cont::ArrayHandle<internal::detail::RecombinedValueType<ComponentType>,
|
||||
vtkm::cont::internal::StorageTagRecombineVec>));
|
||||
|
||||
private:
|
||||
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
|
||||
|
||||
public:
|
||||
vtkm::IdComponent GetNumberOfComponents() const
|
||||
{
|
||||
return StorageType::NumberOfComponents(this->GetBuffers());
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandleStride<ComponentType> GetComponentArray(
|
||||
vtkm::IdComponent componentIndex) const
|
||||
{
|
||||
return StorageType::ArrayForComponent(this->GetBuffers(), componentIndex);
|
||||
}
|
||||
|
||||
void AppendComponentArray(
|
||||
const vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagStride>& array)
|
||||
{
|
||||
StorageType::AppendComponent(this->GetBuffers(), array);
|
||||
}
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <>
|
||||
struct ArrayExtractComponentImpl<vtkm::cont::internal::StorageTagRecombineVec>
|
||||
{
|
||||
template <typename RecombineVec>
|
||||
vtkm::cont::ArrayHandleStride<
|
||||
typename vtkm::VecFlat<typename RecombineVec::ComponentType>::ComponentType>
|
||||
operator()(
|
||||
const vtkm::cont::ArrayHandle<RecombineVec, vtkm::cont::internal::StorageTagRecombineVec>& src,
|
||||
vtkm::IdComponent componentIndex,
|
||||
vtkm::CopyFlag allowCopy) const
|
||||
{
|
||||
using ComponentType = typename RecombineVec::ComponentType;
|
||||
vtkm::cont::ArrayHandleRecombineVec<ComponentType> array(src);
|
||||
constexpr vtkm::IdComponent subComponents = vtkm::VecFlat<ComponentType>::NUM_COMPONENTS;
|
||||
return vtkm::cont::ArrayExtractComponent(
|
||||
array.GetComponentArray(componentIndex / subComponents),
|
||||
componentIndex % subComponents,
|
||||
allowCopy);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
||||
//=============================================================================
|
||||
// Specializations of worklet arguments using ArrayHandleGropuVecVariable
|
||||
#include <vtkm/exec/arg/FetchTagArrayDirectOutArrayHandleRecombineVec.h>
|
||||
|
||||
#endif //vtk_m_cont_ArrayHandleRecombineVec_h
|
@ -163,9 +163,6 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T, typename S>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagReverse<S>);
|
||||
|
||||
/// \brief Reverse the order of an array, on demand.
|
||||
///
|
||||
/// ArrayHandleReverse is a specialization of ArrayHandle. Given an ArrayHandle,
|
||||
|
@ -17,7 +17,6 @@ namespace cont
|
||||
{
|
||||
|
||||
#define VTKM_ARRAYHANDLE_SOA_INSTANTIATE(Type) \
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<Type, StorageTagSOA>; \
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 2>, StorageTagSOA>; \
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 3>, StorageTagSOA>; \
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 4>, StorageTagSOA>;
|
||||
|
@ -128,20 +128,17 @@ struct VTKM_ALWAYS_EXPORT StorageTagSOA
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
class VTKM_ALWAYS_EXPORT Storage<T, vtkm::cont::StorageTagSOA>
|
||||
template <typename ComponentType, vtkm::IdComponent NUM_COMPONENTS>
|
||||
class VTKM_ALWAYS_EXPORT
|
||||
Storage<vtkm::Vec<ComponentType, NUM_COMPONENTS>, vtkm::cont::StorageTagSOA>
|
||||
{
|
||||
VTKM_STATIC_ASSERT(vtkm::HasVecTraits<T>::value);
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
|
||||
using ComponentType = typename VTraits::ComponentType;
|
||||
static constexpr vtkm::IdComponent NUM_COMPONENTS = VTraits::NUM_COMPONENTS;
|
||||
using ValueType = vtkm::Vec<ComponentType, NUM_COMPONENTS>;
|
||||
|
||||
public:
|
||||
using ReadPortalType =
|
||||
vtkm::internal::ArrayPortalSOA<T, vtkm::internal::ArrayPortalBasicRead<ComponentType>>;
|
||||
vtkm::internal::ArrayPortalSOA<ValueType, vtkm::internal::ArrayPortalBasicRead<ComponentType>>;
|
||||
using WritePortalType =
|
||||
vtkm::internal::ArrayPortalSOA<T, vtkm::internal::ArrayPortalBasicWrite<ComponentType>>;
|
||||
vtkm::internal::ArrayPortalSOA<ValueType, vtkm::internal::ArrayPortalBasicWrite<ComponentType>>;
|
||||
|
||||
VTKM_CONT constexpr static vtkm::IdComponent GetNumberOfBuffers() { return NUM_COMPONENTS; }
|
||||
|
||||
@ -204,9 +201,6 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagSOA);
|
||||
|
||||
/// \brief An `ArrayHandle` that for Vecs stores each component in a separate physical array.
|
||||
///
|
||||
/// `ArrayHandleSOA` behaves like a regular `ArrayHandle` (with a basic storage) except that
|
||||
@ -632,7 +626,6 @@ namespace cont
|
||||
{
|
||||
|
||||
#define VTKM_ARRAYHANDLE_SOA_EXPORT(Type) \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<Type, StorageTagSOA>; \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 2>, StorageTagSOA>; \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 3>, StorageTagSOA>; \
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 4>, StorageTagSOA>;
|
||||
|
@ -33,17 +33,17 @@ template class VTKM_CONT_EXPORT Storage<vtkm::Float64, StorageTagStride>;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<char, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Int8, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::UInt8, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Int16, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::UInt16, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Int32, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::UInt32, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Int64, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::UInt64, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Float32, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Float64, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<char, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Int8, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::UInt8, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Int16, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::UInt16, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Int32, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::UInt32, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Int64, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::UInt64, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Float32, StorageTagStride>;
|
||||
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Float64, StorageTagStride>;
|
||||
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
@ -205,10 +205,7 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagStride);
|
||||
|
||||
/// \brief An `ArrayHandle` that access a basic array with strides and offsets.
|
||||
/// \brief An `ArrayHandle` that accesses a basic array with strides and offsets.
|
||||
///
|
||||
/// `ArrayHandleStride` is a simple `ArrayHandle` that accesses data with a prescribed
|
||||
/// stride and offset. You specify the stride and offset at construction. So when a portal
|
||||
@ -393,19 +390,17 @@ extern template class VTKM_CONT_TEMPLATE_EXPORT Storage<vtkm::Float64, StorageTa
|
||||
|
||||
} // namespace internal
|
||||
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<char, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::Int8, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::UInt8, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::Int16, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::UInt16, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::Int32, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::UInt32, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::Int64, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::UInt64, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT
|
||||
ArrayHandleNewStyle<vtkm::Float32, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT
|
||||
ArrayHandleNewStyle<vtkm::Float64, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<char, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Int8, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::UInt8, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Int16, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::UInt16, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Int32, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::UInt32, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Int64, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::UInt64, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Float32, StorageTagStride>;
|
||||
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Float64, StorageTagStride>;
|
||||
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
@ -416,9 +416,6 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T, typename A, typename F, typename IF>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(internal::StorageTagTransform<A, F, IF>));
|
||||
|
||||
/// \brief Implicitly transform values of one array to another with a functor.
|
||||
///
|
||||
/// ArrayHandleTransforms is a specialization of ArrayHandle. It takes a
|
||||
|
@ -37,9 +37,6 @@ struct Storage<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints>
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints);
|
||||
|
||||
/// ArrayHandleUniformPointCoordinates is a specialization of ArrayHandle. It
|
||||
/// contains the information necessary to compute the point coordinates in a
|
||||
/// uniform orthogonal grid (extent, origin, and spacing) and implicitly
|
||||
|
@ -196,10 +196,6 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// This can go away once ArrayHandle is replaced with ArrayHandleNewStyle
|
||||
template <typename T, typename S>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagView<S>);
|
||||
|
||||
template <typename ArrayHandleType>
|
||||
class ArrayHandleView
|
||||
: public vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
|
||||
|
@ -15,9 +15,10 @@
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
|
||||
#include <vtkm/cont/DeviceAdapterTag.h>
|
||||
|
||||
#include <vtkm/cont/StorageVirtual.h>
|
||||
|
||||
#include <vtkm/cont/internal/ArrayHandleDeprecated.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef VTKM_NO_DEPRECATED_VIRTUAL
|
||||
@ -29,8 +30,11 @@ namespace vtkm
|
||||
namespace cont
|
||||
{
|
||||
|
||||
|
||||
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
||||
|
||||
template <typename T>
|
||||
VTKM_ARRAY_HANDLE_DEPRECATED(T, vtkm::cont::StorageTagVirtual);
|
||||
|
||||
template <typename T>
|
||||
class VTKM_ALWAYS_EXPORT VTKM_DEPRECATED(1.6) ArrayHandleVirtual
|
||||
: public vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagVirtual>
|
||||
|
@ -201,10 +201,6 @@ public:
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
template <typename T1, typename S1, typename T2, typename S2>
|
||||
VTKM_ARRAY_HANDLE_NEW_STYLE(VTKM_PASS_COMMAS(vtkm::Pair<T1, T2>),
|
||||
VTKM_PASS_COMMAS(vtkm::cont::StorageTagZip<S1, S2>));
|
||||
|
||||
/// ArrayHandleZip is a specialization of ArrayHandle. It takes two delegate
|
||||
/// array handle and makes a new handle that access the corresponding entries
|
||||
/// in these arrays as a pair.
|
||||
|
@ -74,6 +74,10 @@ VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagBasic);
|
||||
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagBasic);
|
||||
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagBasic);
|
||||
|
||||
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagSOA);
|
||||
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagSOA);
|
||||
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagSOA);
|
||||
|
||||
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_T
|
||||
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC
|
||||
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
|
||||
#include <vtkm/cont/ArrayHandleCompositeVector.h>
|
||||
#include <vtkm/cont/ArrayHandleSOA.h>
|
||||
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
|
||||
#include <vtkm/cont/DeviceAdapterTag.h>
|
||||
|
||||
@ -94,6 +95,10 @@ VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(2, vtkm::cont::StorageTagBasic);
|
||||
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(3, vtkm::cont::StorageTagBasic);
|
||||
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(4, vtkm::cont::StorageTagBasic);
|
||||
|
||||
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(2, vtkm::cont::StorageTagSOA);
|
||||
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(3, vtkm::cont::StorageTagSOA);
|
||||
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(4, vtkm::cont::StorageTagSOA);
|
||||
|
||||
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T
|
||||
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC
|
||||
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T
|
||||
|
@ -33,6 +33,7 @@ set(headers
|
||||
ArrayHandleIndex.h
|
||||
ArrayHandleMultiplexer.h
|
||||
ArrayHandlePermutation.h
|
||||
ArrayHandleRecombineVec.h
|
||||
ArrayHandleReverse.h
|
||||
ArrayHandleRandomStandardNormal.h
|
||||
ArrayHandleRandomUniformBits.h
|
||||
@ -126,7 +127,6 @@ set(headers
|
||||
)
|
||||
|
||||
set(template_sources
|
||||
ArrayHandle.hxx
|
||||
ArrayRangeCompute.hxx # Deprecated, replaced with ArrayRangeComputeTemplate.h
|
||||
CellSetExplicit.hxx
|
||||
CellSetExtrude.hxx
|
||||
@ -217,12 +217,36 @@ endif()
|
||||
vtkm_get_kit_name(kit_name kit_dir)
|
||||
|
||||
# Some custom types included with VTK-m
|
||||
vtkm_option(VTKm_USE_DEFAULT_TYPES_FOR_VTK "Compile VTK-m algorithms for use with types from VTK." OFF)
|
||||
vtkm_option(VTKm_USE_DEFAULT_TYPES_FOR_VTK
|
||||
"Compile VTK-m algorithms for use with types from VTK."
|
||||
OFF
|
||||
)
|
||||
if (VTKm_USE_DEFAULT_TYPES_FOR_VTK)
|
||||
set(VTKm_DEFAULT_TYPES_HEADER "internal/DefaultTypesVTK.h.in")
|
||||
endif()
|
||||
|
||||
mark_as_advanced(VTKm_USE_DEFAULT_TYPES_FOR_VTK)
|
||||
vtkm_option(VTKm_USE_DEFAULT_TYPES_FOR_ASCENT
|
||||
"Compile VTK-m algorithms for use with types from Ascent."
|
||||
OFF
|
||||
)
|
||||
if (VTKm_USE_DEFAULT_TYPES_FOR_ASCENT)
|
||||
set(VTKm_DEFAULT_TYPES_HEADER "internal/DefaultTypesAscent.h.in")
|
||||
if (VTKm_USE_64BIT_IDS)
|
||||
message(SEND_ERROR
|
||||
"When VTKm_USE_DEFAULT_TYPES_FOR_ASCENT is ON, VTKm_USE_64BIT_IDS must be set to OFF"
|
||||
)
|
||||
endif()
|
||||
if (NOT VTKm_USE_DOUBLE_PRECISION)
|
||||
message(SEND_ERROR
|
||||
"When VTKm_USE_DEFAULT_TYPES_FOR_ASCENT is ON, VTKm_USE_DOUBLE_PRECISION must be set to ON"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
mark_as_advanced(
|
||||
VTKm_USE_DEFAULT_TYPES_FOR_VTK
|
||||
VTKm_USE_DEFAULT_TYPES_FOR_ASCENT
|
||||
)
|
||||
|
||||
if (VTKm_DEFAULT_TYPES_HEADER)
|
||||
set(VTK_M_HAS_DEFAULT_TYPES_HEADER TRUE)
|
||||
|
@ -59,13 +59,10 @@ namespace internal
|
||||
using StorageListField = vtkm::ListAppend<
|
||||
vtkm::cont::StorageListBasic,
|
||||
vtkm::List<
|
||||
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag,
|
||||
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<vtkm::Float32>,
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32>,
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32>>::StorageTag,
|
||||
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<vtkm::Float64>,
|
||||
vtkm::cont::ArrayHandle<vtkm::Float64>,
|
||||
vtkm::cont::ArrayHandle<vtkm::Float64>>::StorageTag>>;
|
||||
vtkm::cont::StorageTagUniformPoints,
|
||||
vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
|
||||
vtkm::cont::StorageTagBasic,
|
||||
vtkm::cont::StorageTagBasic>>>;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ namespace cont
|
||||
|
||||
/// constructors for points / whole mesh
|
||||
VTKM_CONT
|
||||
Field::Field(std::string name, Association association, const vtkm::cont::VariantArrayHandle& data)
|
||||
Field::Field(std::string name, Association association, const vtkm::cont::UnknownArrayHandle& data)
|
||||
: Name(name)
|
||||
, FieldAssociation(association)
|
||||
, Data(data)
|
||||
|
@ -58,13 +58,13 @@ public:
|
||||
Field() = default;
|
||||
|
||||
VTKM_CONT
|
||||
Field(std::string name, Association association, const vtkm::cont::VariantArrayHandle& data);
|
||||
Field(std::string name, Association association, const vtkm::cont::UnknownArrayHandle& data);
|
||||
|
||||
template <typename T, typename Storage>
|
||||
VTKM_CONT Field(std::string name,
|
||||
Association association,
|
||||
const vtkm::cont::ArrayHandle<T, Storage>& data)
|
||||
: Field(name, association, vtkm::cont::VariantArrayHandle{ data })
|
||||
: Field(name, association, vtkm::cont::UnknownArrayHandle{ data })
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,16 @@ struct SerializableTypeString<vtkm::Float64>
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct SerializableTypeString<bool>
|
||||
{
|
||||
static VTKM_CONT const std::string& Get()
|
||||
{
|
||||
static std::string name = "B8";
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct SerializableTypeString<char>
|
||||
{
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
|
||||
#include <vtkm/cont/internal/ArrayTransfer.h>
|
||||
#include <vtkm/cont/internal/StorageDeprecated.h>
|
||||
|
||||
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
|
||||
#include <vtkm/cont/tbb/DeviceAdapterTBB.h>
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
#include <vtkm/cont/Storage.h>
|
||||
#include <vtkm/cont/internal/ArrayHandleDeprecated.h>
|
||||
#include <vtkm/cont/internal/StorageDeprecated.h>
|
||||
#include <vtkm/cont/internal/TransferInfo.h>
|
||||
#include <vtkm/internal/ArrayPortalVirtual.h>
|
||||
|
||||
|
@ -12,8 +12,9 @@
|
||||
|
||||
#include <vtkm/cont/StorageVirtual.h>
|
||||
#include <vtkm/cont/TryExecute.h>
|
||||
#include <vtkm/cont/internal/TransferInfo.h>
|
||||
|
||||
#include <vtkm/cont/internal/ArrayTransfer.h>
|
||||
#include <vtkm/cont/internal/TransferInfo.h>
|
||||
#include <vtkm/cont/internal/VirtualObjectTransfer.h>
|
||||
#include <vtkm/cont/internal/VirtualObjectTransferShareWithControl.h>
|
||||
|
||||
|
@ -22,7 +22,24 @@
|
||||
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
|
||||
#include <vtkm/cont/UncertainArrayHandle.h>
|
||||
|
||||
using UnknownSerializationTypes = vtkm::TypeListAll;
|
||||
namespace
|
||||
{
|
||||
|
||||
template <vtkm::IdComponent N, typename ScalarList>
|
||||
struct AllVecImpl;
|
||||
template <vtkm::IdComponent N, typename... Scalars>
|
||||
struct AllVecImpl<N, vtkm::List<Scalars...>>
|
||||
{
|
||||
using type = vtkm::List<vtkm::Vec<Scalars, N>...>;
|
||||
};
|
||||
|
||||
// Normally I would implement this with vtkm::ListTransform, but that is causing an ICE in GCC 4.8.
|
||||
// This implementation is not much different.
|
||||
template <vtkm::IdComponent N>
|
||||
using AllVec = typename AllVecImpl<N, vtkm::TypeListBaseC>::type;
|
||||
|
||||
using UnknownSerializationTypes =
|
||||
vtkm::ListAppend<vtkm::TypeListBaseC, AllVec<2>, AllVec<3>, AllVec<4>>;
|
||||
using UnknownSerializationStorage =
|
||||
vtkm::ListAppend<VTKM_DEFAULT_STORAGE_LIST,
|
||||
vtkm::List<vtkm::cont::StorageTagBasic,
|
||||
@ -41,6 +58,8 @@ using UnknownSerializationStorage =
|
||||
vtkm::cont::StorageTagSOA,
|
||||
vtkm::cont::StorageTagUniformPoints>>;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
@ -59,6 +78,20 @@ std::shared_ptr<UnknownAHContainer> UnknownAHContainer::MakeNewInstance() const
|
||||
return newContainer;
|
||||
}
|
||||
|
||||
bool UnknownAHComponentInfo::operator==(const UnknownAHComponentInfo& rhs)
|
||||
{
|
||||
if (this->IsIntegral || this->IsFloat)
|
||||
{
|
||||
return ((this->IsIntegral == rhs.IsIntegral) && (this->IsFloat == rhs.IsFloat) &&
|
||||
(this->IsSigned == rhs.IsSigned) && (this->Size == rhs.Size));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Needs optimization based on platform. OSX cannot compare typeid across translation units?
|
||||
return this->Type == rhs.Type;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
VTKM_CONT bool UnknownArrayHandle::IsValueTypeImpl(std::type_index type) const
|
||||
@ -83,7 +116,8 @@ VTKM_CONT bool UnknownArrayHandle::IsStorageTypeImpl(std::type_index type) const
|
||||
return this->Container->StorageType == type;
|
||||
}
|
||||
|
||||
VTKM_CONT bool UnknownArrayHandle::IsBaseComponentTypeImpl(std::type_index type) const
|
||||
VTKM_CONT bool UnknownArrayHandle::IsBaseComponentTypeImpl(
|
||||
const detail::UnknownAHComponentInfo& type) const
|
||||
{
|
||||
if (!this->Container)
|
||||
{
|
||||
|
@ -16,11 +16,10 @@
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayHandleCast.h>
|
||||
#include <vtkm/cont/ArrayHandleMultiplexer.h>
|
||||
#include <vtkm/cont/ArrayHandleRecombineVec.h>
|
||||
#include <vtkm/cont/ArrayHandleStride.h>
|
||||
#include <vtkm/cont/DefaultTypes.h>
|
||||
|
||||
#include <vtkm/cont/internal/ArrayPortalFromExtractedComponents.h>
|
||||
|
||||
#include <memory>
|
||||
#include <typeindex>
|
||||
|
||||
@ -143,13 +142,50 @@ struct MakeUnknownAHContainerFunctor
|
||||
std::shared_ptr<UnknownAHContainer> operator()(const vtkm::cont::ArrayHandle<T, S>& array) const;
|
||||
};
|
||||
|
||||
struct VTKM_CONT_EXPORT UnknownAHComponentInfo
|
||||
{
|
||||
std::type_index Type;
|
||||
bool IsIntegral;
|
||||
bool IsFloat;
|
||||
bool IsSigned;
|
||||
std::size_t Size;
|
||||
|
||||
UnknownAHComponentInfo() = delete;
|
||||
|
||||
bool operator==(const UnknownAHComponentInfo& rhs);
|
||||
|
||||
template <typename T>
|
||||
static UnknownAHComponentInfo Make()
|
||||
{
|
||||
return UnknownAHComponentInfo{ typeid(T),
|
||||
std::is_integral<T>::value,
|
||||
std::is_floating_point<T>::value,
|
||||
std::is_signed<T>::value,
|
||||
sizeof(T) };
|
||||
}
|
||||
|
||||
private:
|
||||
UnknownAHComponentInfo(std::type_index&& type,
|
||||
bool isIntegral,
|
||||
bool isFloat,
|
||||
bool isSigned,
|
||||
std::size_t size)
|
||||
: Type(std::move(type))
|
||||
, IsIntegral(isIntegral)
|
||||
, IsFloat(isFloat)
|
||||
, IsSigned(isSigned)
|
||||
, Size(size)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct VTKM_CONT_EXPORT UnknownAHContainer
|
||||
{
|
||||
void* ArrayHandlePointer;
|
||||
|
||||
std::type_index ValueType;
|
||||
std::type_index StorageType;
|
||||
std::type_index BaseComponentType;
|
||||
UnknownAHComponentInfo BaseComponentType;
|
||||
|
||||
using DeleteType = void(void*);
|
||||
DeleteType* DeleteFunction;
|
||||
@ -248,7 +284,8 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle<T, S
|
||||
: ArrayHandlePointer(new vtkm::cont::ArrayHandle<T, S>(array))
|
||||
, ValueType(typeid(T))
|
||||
, StorageType(typeid(S))
|
||||
, BaseComponentType(typeid(typename vtkm::VecTraits<T>::BaseComponentType))
|
||||
, BaseComponentType(
|
||||
UnknownAHComponentInfo::Make<typename vtkm::VecTraits<T>::BaseComponentType>())
|
||||
, DeleteFunction(detail::UnknownAHDelete<T, S>)
|
||||
, NewInstance(detail::UnknownADNewInstance<T, S>)
|
||||
, NewInstanceBasic(detail::UnknownADNewInstanceBasic<T>)
|
||||
@ -312,7 +349,7 @@ class VTKM_CONT_EXPORT UnknownArrayHandle
|
||||
|
||||
VTKM_CONT bool IsValueTypeImpl(std::type_index type) const;
|
||||
VTKM_CONT bool IsStorageTypeImpl(std::type_index type) const;
|
||||
VTKM_CONT bool IsBaseComponentTypeImpl(std::type_index type) const;
|
||||
VTKM_CONT bool IsBaseComponentTypeImpl(const detail::UnknownAHComponentInfo& type) const;
|
||||
|
||||
public:
|
||||
VTKM_CONT UnknownArrayHandle() = default;
|
||||
@ -388,7 +425,7 @@ public:
|
||||
template <typename BaseComponentType>
|
||||
VTKM_CONT bool IsBaseComponentType() const
|
||||
{
|
||||
return this->IsBaseComponentTypeImpl(typeid(BaseComponentType));
|
||||
return this->IsBaseComponentTypeImpl(detail::UnknownAHComponentInfo::Make<BaseComponentType>());
|
||||
}
|
||||
|
||||
/// Returns true if this array matches the ArrayHandleType template argument.
|
||||
@ -425,8 +462,7 @@ public:
|
||||
/// If the array holds `Vec`-like objects that have the number of components that can vary
|
||||
/// at runtime, this method will return 0 (because there is no consistent answer).
|
||||
///
|
||||
VTKM_CONT VTKM_DEPRECATED(1.6, "Use GetNumberOfComponentsFlat.") vtkm::IdComponent
|
||||
GetNumberOfComponents() const;
|
||||
VTKM_CONT vtkm::IdComponent GetNumberOfComponents() const;
|
||||
|
||||
/// \brief Returns the total number of components for each value in the array.
|
||||
///
|
||||
@ -553,61 +589,96 @@ public:
|
||||
return ComponentArrayType(buffers);
|
||||
}
|
||||
|
||||
///@{
|
||||
/// \brief Convenience portal to access all components (in control environment).
|
||||
/// \brief Extract the array knowing only the component type of the array.
|
||||
///
|
||||
/// This method returns a portal that allows you to access all the values in the contained
|
||||
/// portal by knowing only the type of the base component. The `BaseComponentType` has to
|
||||
/// be specified and must match the contained array (i.e.the result of `IsBaseComponentType`
|
||||
/// must succeed for the given type).
|
||||
/// This method returns an `ArrayHandle` that points to the data in the array. This method
|
||||
/// differs from `AsArrayHandle` because you do not need to know the exact `ValueType` and
|
||||
/// `StorageTag` of the array. Instead, you only need to know the base component type.
|
||||
///
|
||||
/// Note that the returned portal is not thread safe, but you may safely create multiple portals
|
||||
/// for multiple threads.
|
||||
/// `ExtractArrayFromComponents` works by calling the `ExtractComponent` method and then
|
||||
/// combining them together in a fancy `ArrayHandle`. This allows you to ignore the storage
|
||||
/// type of the underlying array as well as any `Vec` structure of the value type. However,
|
||||
/// it also places some limitations on how the data can be pulled from the data.
|
||||
///
|
||||
/// First, you have to specify the base component type. This must match the data in the
|
||||
/// underlying array (as reported by `IsBaseComponentType`).
|
||||
///
|
||||
/// Second, the array returned will have the `Vec`s flattened. For example, if the underlying
|
||||
/// array has a `ValueType` of `Vec<Vec<T, 3>, 3>`, then this method will tread the data as
|
||||
/// if it was `Vec<T, 9>`. There is no way to get an array with `Vec` of `Vec` values.
|
||||
///
|
||||
/// Third, because the `Vec` length of the values in the returned `ArrayHandle` must be
|
||||
/// determined at runtime, that can break many assumptions of using `Vec` objects. The
|
||||
/// type is not going to be a `Vec<T,N>` type but rather an internal class that is intended
|
||||
/// to behave like that. The type should behave mostly like a `Vec`, but will have some
|
||||
/// differences that can lead to unexpected behavior. For example, this `Vec`-like object
|
||||
/// will not have a `NUM_COMPONENTS` constant static expression because it is not known
|
||||
/// at compile time. (Use the `GetNumberOfComponents` method instead.) And for the same
|
||||
/// reason you will not be able to pass these objects to classes overloaded or templated
|
||||
/// on the `Vec` type. Also, these `Vec`-like objects cannot be created as new instances.
|
||||
/// Thus, you will likely have to iterate over all components rather than do operations on
|
||||
/// the whole `Vec`.
|
||||
///
|
||||
/// Fourth, because `ExtractArrayFromComponents` uses `ExtractComponent` to pull data from
|
||||
/// the array (which in turn uses `ArrayExtractComponent`), there are some `ArrayHandle` types
|
||||
/// that will require copying data to a new array. This could be problematic in cases where
|
||||
/// you want to write to the array. To prevent data from being copied, set the optional
|
||||
/// `allowCopy` to `vtkm::CopyFlag::Off`. This will cause an exception to be thrown if
|
||||
/// the resulting array cannot reference the memory held in this `UnknownArrayHandle`.
|
||||
///
|
||||
/// Fifth, component arrays are extracted using `ArrayHandleStride` as the representation
|
||||
/// for each component. This array adds a slight overhead for each lookup as it performs the
|
||||
/// arithmetic for finding the index of each component.
|
||||
///
|
||||
template <typename BaseComponentType>
|
||||
VTKM_CONT vtkm::cont::internal::ArrayPortalFromExtractedComponents<
|
||||
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::ReadPortalType>
|
||||
ReadPortalForBaseComponentType() const
|
||||
VTKM_CONT vtkm::cont::ArrayHandleRecombineVec<BaseComponentType> ExtractArrayFromComponents(
|
||||
vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) const
|
||||
{
|
||||
vtkm::cont::ArrayHandleRecombineVec<BaseComponentType> result;
|
||||
vtkm::IdComponent numComponents = this->GetNumberOfComponentsFlat();
|
||||
vtkm::cont::internal::ArrayPortalFromExtractedComponents<
|
||||
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::ReadPortalType>
|
||||
portal(numComponents);
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
|
||||
{
|
||||
auto array = this->ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::On);
|
||||
portal.AddArray(array, array.ReadPortal());
|
||||
result.AppendComponentArray(this->ExtractComponent<BaseComponentType>(cIndex, allowCopy));
|
||||
}
|
||||
return portal;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename BaseComponentType>
|
||||
VTKM_CONT vtkm::cont::internal::ArrayPortalFromExtractedComponents<
|
||||
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::WritePortalType>
|
||||
WritePortalForBaseComponentType() const
|
||||
{
|
||||
vtkm::IdComponent numComponents = this->GetNumberOfComponentsFlat();
|
||||
vtkm::cont::internal::ArrayPortalFromExtractedComponents<
|
||||
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::WritePortalType>
|
||||
portal(numComponents);
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
|
||||
{
|
||||
auto array = this->ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::Off);
|
||||
portal.AddArray(array, array.WritePortal());
|
||||
}
|
||||
return portal;
|
||||
}
|
||||
///@}
|
||||
|
||||
/// \brief Call a functor using the underlying array type.
|
||||
///
|
||||
/// `CastAndCall` attempts to cast the held array to a specific value type,
|
||||
/// `CastAndCallForTypes` attempts to cast the held array to a specific value type,
|
||||
/// and then calls the given functor with the cast array. You must specify
|
||||
/// the `TypeList` and `StorageList` as template arguments.
|
||||
///
|
||||
/// After the functor argument you may add any number of arguments that will be
|
||||
/// passed to the functor after the converted `ArrayHandle`.
|
||||
///
|
||||
template <typename TypeList, typename StorageList, typename Functor, typename... Args>
|
||||
VTKM_CONT void CastAndCallForTypes(Functor&& functor, Args&&... args) const;
|
||||
|
||||
/// \brief Call a functor on an array extracted from the components.
|
||||
///
|
||||
/// `CastAndCallWithExtractedArray` behaves similarly to `CastAndCallForTypes`.
|
||||
/// It converts the contained data to an `ArrayHandle` and calls a functor with
|
||||
/// that `ArrayHandle` (and any number of optionally specified arguments).
|
||||
///
|
||||
/// The advantage of `CastAndCallWithExtractedArray` is that you do not need to
|
||||
/// specify any `TypeList` or `StorageList`. Instead, it internally uses
|
||||
/// `ExtractArrayFromComponents` to work with most `ArrayHandle` types with only
|
||||
/// about 10 instances of the functor. In contrast, calling `CastAndCallForTypes`
|
||||
/// with, for example, `VTKM_DEFAULT_TYPE_LIST` and `VTKM_DEFAULT_STORAGE_LIST`
|
||||
/// results in many more instances of the functor but handling many fewer types
|
||||
/// of `ArrayHandle`.
|
||||
///
|
||||
/// There are, however, costs to using this method. Details of these costs are
|
||||
/// documented for the `ExtractArrayFromComponents` method, but briefly they
|
||||
/// are that `Vec` types get flattened, the resulting array has a strange `Vec`-like
|
||||
/// value type that has many limitations on its use, there is an overhead for
|
||||
/// retrieving each value from the array, and there is a potential that data
|
||||
/// must be copied.
|
||||
///
|
||||
template <typename Functor, typename... Args>
|
||||
VTKM_CONT void CastAndCallWithExtractedArray(Functor&& functor, Args&&... args) const;
|
||||
|
||||
/// Releases any resources being used in the execution environment (that are
|
||||
/// not being shared by the control environment).
|
||||
///
|
||||
@ -776,10 +847,8 @@ VTKM_CONT_EXPORT void ThrowCastAndCallException(const vtkm::cont::UnknownArrayHa
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
|
||||
template <typename TypeList, typename StorageTagList, typename Functor, typename... Args>
|
||||
VTKM_CONT void UnknownArrayHandle::CastAndCallForTypes(Functor&& f, Args&&... args) const
|
||||
inline void UnknownArrayHandle::CastAndCallForTypes(Functor&& f, Args&&... args) const
|
||||
{
|
||||
using crossProduct = detail::ListAllArrayTypes<TypeList, StorageTagList>;
|
||||
|
||||
@ -805,6 +874,59 @@ void CastAndCall(const UnknownArrayHandle& handle, Functor&& f, Args&&... args)
|
||||
std::forward<Functor>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct UnknownArrayHandleTryExtract
|
||||
{
|
||||
template <typename T, typename Functor, typename... Args>
|
||||
void operator()(T,
|
||||
Functor&& f,
|
||||
bool& called,
|
||||
const vtkm::cont::UnknownArrayHandle& unknownArray,
|
||||
Args&&... args) const
|
||||
{
|
||||
if (!called && unknownArray.IsBaseComponentType<T>())
|
||||
{
|
||||
called = true;
|
||||
auto extractedArray = unknownArray.ExtractArrayFromComponents<T>();
|
||||
VTKM_LOG_CAST_SUCC(unknownArray, extractedArray);
|
||||
|
||||
// If you get a compile error here, it means that you have called
|
||||
// CastAndCallWithExtractedArray for a vtkm::cont::UnknownArrayHandle and the arguments of
|
||||
// the functor do not match those being passed. This is often because it is calling the
|
||||
// functor with an ArrayHandle type that was not expected. Add overloads to the functor to
|
||||
// accept all possible array types or constrain the types tried for the CastAndCall. Note
|
||||
// that the functor will be called with an array of type that is different than the actual
|
||||
// type of the `ArrayHandle` stored in the `UnknownArrayHandle`.
|
||||
f(extractedArray, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Functor, typename... Args>
|
||||
inline void UnknownArrayHandle::CastAndCallWithExtractedArray(Functor&& functor,
|
||||
Args&&... args) const
|
||||
{
|
||||
bool called = false;
|
||||
vtkm::ListForEach(detail::UnknownArrayHandleTryExtract{},
|
||||
vtkm::TypeListScalarAll{},
|
||||
std::forward<Functor>(functor),
|
||||
called,
|
||||
*this,
|
||||
std::forward<Args>(args)...);
|
||||
if (!called)
|
||||
{
|
||||
// Throw an exception.
|
||||
// The message will be a little wonky because the types are just the value types, not the
|
||||
// full type to cast to.
|
||||
VTKM_LOG_CAST_FAIL(*this, vtkm::TypeListScalarAll);
|
||||
detail::ThrowCastAndCallException(*this, typeid(vtkm::TypeListScalarAll));
|
||||
}
|
||||
}
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
|
1355
vtkm/cont/internal/ArrayHandleDeprecated.h
Normal file
1355
vtkm/cont/internal/ArrayHandleDeprecated.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,96 +0,0 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_cont_internal_ArrayPortalFromExtractedComponents_h
|
||||
#define vtk_m_cont_internal_ArrayPortalFromExtractedComponents_h
|
||||
|
||||
#include <vtkm/cont/ArrayHandleStride.h>
|
||||
|
||||
#include <vtkm/internal/ArrayPortalHelpers.h>
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/VecTraits.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
class UnknownArrayHandle;
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
/// `ArrayPortalFromExtractedComponents` is a convenience class that allows you to treat
|
||||
/// a group of arrays that were extracted from the components of an array and treat them
|
||||
/// like a portal to the array itself. It is used internally by `UnknownArrayHandle` to
|
||||
/// get read and write portals to the array
|
||||
///
|
||||
/// Note that this portal only works on the control environment.
|
||||
///
|
||||
template <typename PortalType>
|
||||
class ArrayPortalFromExtractedComponents
|
||||
{
|
||||
private:
|
||||
using T = typename PortalType::ValueType;
|
||||
std::vector<vtkm::cont::ArrayHandleStride<T>> Arrays;
|
||||
std::vector<PortalType> Portals;
|
||||
mutable std::vector<T> Values;
|
||||
|
||||
friend UnknownArrayHandle;
|
||||
|
||||
void AddArray(const vtkm::cont::ArrayHandleStride<T>& array, const PortalType& portal)
|
||||
{
|
||||
this->Arrays.push_back(array);
|
||||
this->Portals.push_back(portal);
|
||||
}
|
||||
|
||||
public:
|
||||
using ValueType = vtkm::VecCConst<T>;
|
||||
|
||||
ArrayPortalFromExtractedComponents(vtkm::IdComponent expectedArrays = 0)
|
||||
{
|
||||
this->Arrays.reserve(static_cast<std::size_t>(expectedArrays));
|
||||
this->Portals.reserve(static_cast<std::size_t>(expectedArrays));
|
||||
}
|
||||
|
||||
VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Portals[0].GetNumberOfValues(); }
|
||||
|
||||
VTKM_CONT ValueType Get(vtkm::Id index) const
|
||||
{
|
||||
// Note: this is not thread-safe
|
||||
this->Values.clear();
|
||||
for (auto&& portal : this->Portals)
|
||||
{
|
||||
this->Values.push_back(portal.Get(index));
|
||||
}
|
||||
return ValueType(this->Values.data(), static_cast<vtkm::IdComponent>(this->Values.size()));
|
||||
}
|
||||
|
||||
template <typename VecType,
|
||||
typename Writable = vtkm::internal::PortalSupportsSets<PortalType>,
|
||||
typename = typename std::enable_if<Writable::value>::type>
|
||||
VTKM_CONT void Set(vtkm::Id index, const VecType& value) const
|
||||
{
|
||||
using Traits = vtkm::VecTraits<VecType>;
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::GetNumberOfComponents(value); ++cIndex)
|
||||
{
|
||||
this->Portals[static_cast<std::size_t>(cIndex)].Set(index,
|
||||
Traits::GetComponent(value, index));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::cont::internal
|
||||
|
||||
#endif //vtk_m_cont_internal_ArrayPortalFromExtractedComponents_h
|
@ -110,17 +110,6 @@ struct MetaDataManager
|
||||
|
||||
MetaDataManager() = default;
|
||||
|
||||
MetaDataManager(void* data,
|
||||
const std::string& type,
|
||||
vtkm::cont::internal::detail::DeleterType* deleter,
|
||||
vtkm::cont::internal::detail::CopierType* copier)
|
||||
: Data(data)
|
||||
, Type(type)
|
||||
, Deleter(deleter)
|
||||
, Copier(copier)
|
||||
{
|
||||
}
|
||||
|
||||
~MetaDataManager()
|
||||
{
|
||||
if (this->Data != nullptr)
|
||||
@ -131,20 +120,23 @@ struct MetaDataManager
|
||||
}
|
||||
}
|
||||
|
||||
MetaDataManager(const MetaDataManager& src)
|
||||
// We don't know how much information is the metadata, and copying it could be expensive.
|
||||
// Thus, we want to be intentional about copying the metadata only for deep copies.
|
||||
MetaDataManager(const MetaDataManager& src) = delete;
|
||||
MetaDataManager& operator=(const MetaDataManager& src) = delete;
|
||||
|
||||
void Initialize(void* data,
|
||||
const std::string& type,
|
||||
vtkm::cont::internal::detail::DeleterType* deleter,
|
||||
vtkm::cont::internal::detail::CopierType* copier)
|
||||
{
|
||||
if (src.Data != nullptr)
|
||||
{
|
||||
VTKM_ASSERT(src.Copier);
|
||||
VTKM_ASSERT(src.Deleter);
|
||||
this->Data = src.Copier(src.Data);
|
||||
this->Type = src.Type;
|
||||
this->Deleter = src.Deleter;
|
||||
this->Copier = src.Copier;
|
||||
}
|
||||
Data = data;
|
||||
Type = type;
|
||||
Deleter = deleter;
|
||||
Copier = copier;
|
||||
}
|
||||
|
||||
MetaDataManager& operator=(const MetaDataManager& src)
|
||||
void DeepCopyFrom(const MetaDataManager& src)
|
||||
{
|
||||
if (this->Data != nullptr)
|
||||
{
|
||||
@ -162,7 +154,6 @@ struct MetaDataManager
|
||||
this->Deleter = src.Deleter;
|
||||
this->Copier = src.Copier;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
@ -599,7 +590,7 @@ struct VTKM_NEVER_EXPORT BufferHelper
|
||||
srcInternals->GetHostBuffer(srcLock).GetPointer(),
|
||||
static_cast<std::size_t>(size));
|
||||
|
||||
destInternals->MetaData = srcInternals->MetaData;
|
||||
destInternals->MetaData.DeepCopyFrom(srcInternals->MetaData);
|
||||
}
|
||||
|
||||
static void CopyOnDevice(
|
||||
@ -641,7 +632,7 @@ struct VTKM_NEVER_EXPORT BufferHelper
|
||||
|
||||
destInternals->SetNumberOfBytes(destLock, srcInternals->GetNumberOfBytes(srcLock));
|
||||
|
||||
destInternals->MetaData = srcInternals->MetaData;
|
||||
destInternals->MetaData.DeepCopyFrom(srcInternals->MetaData);
|
||||
}
|
||||
};
|
||||
|
||||
@ -710,7 +701,7 @@ void Buffer::SetMetaData(void* data,
|
||||
detail::DeleterType* deleter,
|
||||
detail::CopierType* copier) const
|
||||
{
|
||||
this->Internals->MetaData = MetaDataManager(data, type, deleter, copier);
|
||||
this->Internals->MetaData.Initialize(data, type, deleter, copier);
|
||||
}
|
||||
|
||||
void* Buffer::GetMetaData(const std::string& type) const
|
||||
@ -881,7 +872,7 @@ void Buffer::DeepCopyFrom(const vtkm::cont::internal::Buffer& src) const
|
||||
src.Internals->GetNumberOfBytes(srcLock),
|
||||
vtkm::CopyFlag::Off,
|
||||
token);
|
||||
dest.Internals->MetaData = src.Internals->MetaData;
|
||||
dest.Internals->MetaData.DeepCopyFrom(src.Internals->MetaData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,8 @@
|
||||
##============================================================================
|
||||
|
||||
set(headers
|
||||
ArrayHandleDeprecated.h
|
||||
ArrayHandleExecutionManager.h
|
||||
ArrayPortalFromExtractedComponents.h
|
||||
ArrayPortalFromIterators.h
|
||||
ArrayTransfer.h
|
||||
AtomicInterfaceControl.h
|
||||
|
69
vtkm/cont/internal/DefaultTypesAscent.h.in
Normal file
69
vtkm/cont/internal/DefaultTypesAscent.h.in
Normal file
@ -0,0 +1,69 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_cont_internal_DefaultTypesAscent_h
|
||||
#define vtk_m_cont_internal_DefaultTypesAscent_h
|
||||
|
||||
#include <vtkm/TypeList.h>
|
||||
#include <vtkm/Types.h>
|
||||
|
||||
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
|
||||
#include <vtkm/cont/ArrayHandleSOA.h>
|
||||
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
|
||||
#include <vtkm/cont/StorageList.h>
|
||||
|
||||
#ifdef VTKM_USE_64BIT_IDS
|
||||
#error "VTK-m must be compiled with VTKM_USE_64BITS_IDS set to OFF for Ascent."
|
||||
#endif
|
||||
|
||||
#ifndef VTKM_USE_DOUBLE_PRECISION
|
||||
#error "VTK-m must be compiled with VTKM_USE_DOUBLE_PRECISION to ON for Ascent."
|
||||
#endif
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
|
||||
// Default value types for fields in Ascent.
|
||||
using TypeListAscent = vtkm::List<vtkm::FloatDefault,
|
||||
vtkm::Vec3f,
|
||||
// We should not need Float32 types, but currently the tests need
|
||||
// them. We should remove these types once we are able to "fix"
|
||||
// the tests by converting to supported default types.
|
||||
vtkm::Float32,
|
||||
vtkm::Vec3f_32>;
|
||||
|
||||
}
|
||||
} // namespace vtkm::internal
|
||||
|
||||
#define VTKM_DEFAULT_TYPE_LIST ::vtkm::internal::TypeListAscent
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
|
||||
using StorageListAscent = vtkm::List<
|
||||
vtkm::cont::StorageTagBasic, // Basic storage should always be included
|
||||
vtkm::cont::StorageTagSOA, // Support separate arrays for each component
|
||||
vtkm::cont::StorageTagUniformPoints, // Support uniform structured grids
|
||||
vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic, // Support rectilinear grids
|
||||
vtkm::cont::StorageTagBasic,
|
||||
vtkm::cont::StorageTagBasic>>;
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::cont::internal
|
||||
|
||||
#define VTKM_DEFAULT_STORAGE_LIST ::vtkm::cont::internal::StorageListAscent
|
||||
|
||||
#endif //vtk_m_cont_internal_DefaultTypesAscent_h
|
@ -7,8 +7,8 @@
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
#ifndef vtkmDefaultTypes_h
|
||||
#define vtkmDefaultTypes_h
|
||||
#ifndef vtk_m_cont_internal_DefaultTypesVTK_h
|
||||
#define vtk_m_cont_internal_DefaultTypesVTK_h
|
||||
|
||||
// This configures the default types to use when compiling VTK-m for use as an
|
||||
// accelerator in VTK.
|
||||
@ -105,4 +105,4 @@ using CellListAllOutVTK = vtkm::ListAppend<CellListStructuredOutVTK, CellListUns
|
||||
#define VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED ::tovtkm::CellListStructuredInVTK
|
||||
#define VTKM_DEFAULT_CELL_SET_LIST_UNSTRUCTURED ::tovtkm::CellListUnstructuredInVTK
|
||||
|
||||
#endif //vtkmDefaultTypes_h
|
||||
#endif //vtk_m_cont_internal_DefaultTypesVTK_h
|
||||
|
@ -12,8 +12,8 @@
|
||||
#define vtk_m_cont_internal_DeviceAdapterAlgorithmGeneral_h
|
||||
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayHandleDecorator.h>
|
||||
#include <vtkm/cont/ArrayHandleDiscard.h>
|
||||
#include <vtkm/cont/ArrayHandleImplicit.h>
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/ArrayHandleView.h>
|
||||
#include <vtkm/cont/ArrayHandleZip.h>
|
||||
@ -529,6 +529,33 @@ public:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Reduce
|
||||
private:
|
||||
template <typename T, typename BinaryFunctor>
|
||||
class ReduceDecoratorImpl
|
||||
{
|
||||
public:
|
||||
VTKM_CONT ReduceDecoratorImpl() = default;
|
||||
|
||||
VTKM_CONT
|
||||
ReduceDecoratorImpl(const T& initialValue, const BinaryFunctor& binaryFunctor)
|
||||
: InitialValue(initialValue)
|
||||
, ReduceOperator(binaryFunctor)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Portal>
|
||||
VTKM_CONT ReduceKernel<Portal, T, BinaryFunctor> CreateFunctor(const Portal& portal) const
|
||||
{
|
||||
return ReduceKernel<Portal, T, BinaryFunctor>(
|
||||
portal, this->InitialValue, this->ReduceOperator);
|
||||
}
|
||||
|
||||
private:
|
||||
T InitialValue;
|
||||
BinaryFunctor ReduceOperator;
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename T, typename U, class CIn>
|
||||
VTKM_CONT static U Reduce(const vtkm::cont::ArrayHandle<T, CIn>& input, U initialValue)
|
||||
{
|
||||
@ -544,24 +571,16 @@ public:
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
vtkm::cont::Token token;
|
||||
|
||||
//Crazy Idea:
|
||||
//We create a implicit array handle that wraps the input
|
||||
//array handle. The implicit functor is passed the input array handle, and
|
||||
//the number of elements it needs to sum. This way the implicit handle
|
||||
//acts as the first level reduction. Say for example reducing 16 values
|
||||
//at a time.
|
||||
//
|
||||
//Now that we have an implicit array that is 1/16 the length of full array
|
||||
//we can use scan inclusive to compute the final sum
|
||||
auto inputPortal = input.PrepareForInput(DeviceAdapterTag(), token);
|
||||
ReduceKernel<decltype(inputPortal), U, BinaryFunctor> kernel(
|
||||
inputPortal, initialValue, binary_functor);
|
||||
|
||||
//We perform the reduction in two levels. The first level is performed by
|
||||
//an `ArrayHandleDecorator` which reduces 16 input values and maps them to
|
||||
//one value. The decorator array is then 1/16 the length of the input array,
|
||||
//and we can use inclusive scan as the second level to compute the final
|
||||
//result.
|
||||
vtkm::Id length = (input.GetNumberOfValues() / 16);
|
||||
length += (input.GetNumberOfValues() % 16 == 0) ? 0 : 1;
|
||||
auto reduced = vtkm::cont::make_ArrayHandleImplicit(kernel, length);
|
||||
auto reduced = vtkm::cont::make_ArrayHandleDecorator(
|
||||
length, ReduceDecoratorImpl<U, BinaryFunctor>(initialValue, binary_functor), input);
|
||||
|
||||
vtkm::cont::ArrayHandle<U, vtkm::cont::StorageTagBasic> inclusiveScanStorage;
|
||||
const U scanResult =
|
||||
|
@ -25,12 +25,12 @@ namespace vtkm
|
||||
namespace cont
|
||||
{
|
||||
|
||||
template <typename T, typename S>
|
||||
class ArrayHandle;
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename T, typename S>
|
||||
class ArrayHandleDeprecated;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
@ -98,7 +98,7 @@ class StorageDeprecated
|
||||
using T = typename detail::StorageTemplateParams<StorageType>::ValueType;
|
||||
using StorageTag = typename detail::StorageTemplateParams<StorageType>::StorageTag;
|
||||
|
||||
using ArrayType = vtkm::cont::ArrayHandle<T, StorageTag>;
|
||||
using ArrayType = vtkm::cont::internal::ArrayHandleDeprecated<T, StorageTag>;
|
||||
|
||||
VTKM_CONT static ArrayType GetArray(const vtkm::cont::internal::Buffer* buffers)
|
||||
{
|
||||
|
@ -8,6 +8,7 @@
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/cont/internal/ArrayPortalFromIterators.h>
|
||||
#include <vtkm/cont/internal/Buffer.h>
|
||||
|
||||
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
|
||||
|
@ -10,10 +10,9 @@
|
||||
#ifndef vtk_m_cont_kokkos_internal_DeviceAdapterAlgorithmKokkos_h
|
||||
#define vtk_m_cont_kokkos_internal_DeviceAdapterAlgorithmKokkos_h
|
||||
|
||||
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
|
||||
|
||||
#include <vtkm/cont/ArrayHandleImplicit.h>
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
|
||||
#include <vtkm/cont/ErrorExecution.h>
|
||||
#include <vtkm/cont/internal/DeviceAdapterAlgorithmGeneral.h>
|
||||
#include <vtkm/cont/vtkm_cont_export.h>
|
||||
@ -164,6 +163,7 @@ struct ReductionIdentity<vtkm::BitwiseOr, ResultType>
|
||||
}
|
||||
} // kokkos::internal
|
||||
|
||||
//=============================================================================
|
||||
template <>
|
||||
struct DeviceAdapterAlgorithm<vtkm::cont::DeviceAdapterTagKokkos>
|
||||
: vtkm::cont::internal::DeviceAdapterAlgorithmGeneral<
|
||||
@ -208,6 +208,7 @@ public:
|
||||
vtkm::Id{ 0 });
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
using Superclass::Copy;
|
||||
|
||||
template <typename T>
|
||||
@ -227,66 +228,104 @@ public:
|
||||
Kokkos::deep_copy(vtkm::cont::kokkos::internal::GetExecutionSpaceInstance(), viewOut, viewIn);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
private:
|
||||
template <typename ArrayHandle, typename BinaryFunctor, typename ResultType>
|
||||
template <typename ArrayHandle, typename BinaryOperator, typename ResultType>
|
||||
VTKM_CONT static ResultType ReduceImpl(const ArrayHandle& input,
|
||||
BinaryFunctor binary_functor,
|
||||
BinaryOperator binaryOperator,
|
||||
ResultType initialValue,
|
||||
std::false_type)
|
||||
{
|
||||
return Superclass::Reduce(input, initialValue, binary_functor);
|
||||
return Superclass::Reduce(input, initialValue, binaryOperator);
|
||||
}
|
||||
|
||||
template <typename ArrayPortal, typename BinaryFunctor, typename ResultType>
|
||||
class ReduceFunctor
|
||||
template <typename BinaryOperator, typename FunctorOperator, typename ResultType>
|
||||
class KokkosReduceFunctor
|
||||
{
|
||||
public:
|
||||
using size_type = vtkm::Id;
|
||||
using value_type = ResultType;
|
||||
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
ReduceFunctor() {}
|
||||
KokkosReduceFunctor() {}
|
||||
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
explicit ReduceFunctor(const ArrayPortal& portal, const BinaryFunctor& op)
|
||||
: Portal(portal)
|
||||
, Operator(op)
|
||||
template <typename... Args>
|
||||
KOKKOS_INLINE_FUNCTION explicit KokkosReduceFunctor(const BinaryOperator& op, Args... args)
|
||||
: Operator(op)
|
||||
, Functor(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
void operator()(const size_type i, value_type& update) const
|
||||
{
|
||||
update = this->Operator(update, this->Portal.Get(i));
|
||||
}
|
||||
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
void join(volatile value_type& dst, const volatile value_type& src) const
|
||||
{
|
||||
dst = this->Operator(dst, src);
|
||||
}
|
||||
|
||||
KOKKOS_INLINE_FUNCTION void init(value_type& dst) const
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
void init(value_type& dst) const
|
||||
{
|
||||
dst = kokkos::internal::ReductionIdentity<BinaryFunctor, value_type>::value;
|
||||
dst = kokkos::internal::ReductionIdentity<BinaryOperator, value_type>::value;
|
||||
}
|
||||
|
||||
// Reduce operator
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
void operator()(vtkm::Id i, ResultType& update) const
|
||||
{
|
||||
this->Functor(this->Operator, i, update);
|
||||
}
|
||||
|
||||
// Scan operator
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
void operator()(vtkm::Id i, ResultType& update, const bool final) const
|
||||
{
|
||||
this->Functor(this->Operator, i, update, final);
|
||||
}
|
||||
|
||||
private:
|
||||
BinaryOperator Operator;
|
||||
FunctorOperator Functor;
|
||||
};
|
||||
|
||||
template <typename ArrayPortal, typename BinaryOperator, typename ResultType>
|
||||
class ReduceOperator
|
||||
{
|
||||
public:
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
ReduceOperator() {}
|
||||
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
explicit ReduceOperator(const ArrayPortal& portal)
|
||||
: Portal(portal)
|
||||
{
|
||||
}
|
||||
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
void operator()(const BinaryOperator& op, vtkm::Id i, ResultType& update) const
|
||||
{
|
||||
update = op(update, this->Portal.Get(i));
|
||||
}
|
||||
|
||||
private:
|
||||
ArrayPortal Portal;
|
||||
BinaryFunctor Operator;
|
||||
};
|
||||
|
||||
template <typename ArrayHandle, typename BinaryFunctor, typename ResultType>
|
||||
template <typename BinaryOperator, typename ArrayPortal, typename ResultType>
|
||||
using ReduceFunctor = KokkosReduceFunctor<BinaryOperator,
|
||||
ReduceOperator<ArrayPortal, BinaryOperator, ResultType>,
|
||||
ResultType>;
|
||||
|
||||
template <typename ArrayHandle, typename BinaryOperator, typename ResultType>
|
||||
VTKM_CONT static ResultType ReduceImpl(const ArrayHandle& input,
|
||||
BinaryFunctor binary_functor,
|
||||
BinaryOperator binaryOperator,
|
||||
ResultType initialValue,
|
||||
std::true_type)
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
auto inputPortal = input.PrepareForInput(vtkm::cont::DeviceAdapterTagKokkos{}, token);
|
||||
|
||||
ReduceFunctor<decltype(inputPortal), BinaryFunctor, ResultType> functor(inputPortal,
|
||||
binary_functor);
|
||||
ReduceFunctor<BinaryOperator, decltype(inputPortal), ResultType> functor(binaryOperator,
|
||||
inputPortal);
|
||||
|
||||
ResultType result;
|
||||
|
||||
@ -294,36 +333,47 @@ private:
|
||||
vtkm::cont::kokkos::internal::GetExecutionSpaceInstance(), 0, input.GetNumberOfValues());
|
||||
Kokkos::parallel_reduce(policy, functor, result);
|
||||
|
||||
return binary_functor(initialValue, result);
|
||||
return binaryOperator(initialValue, result);
|
||||
}
|
||||
|
||||
template <bool P1, typename BinaryFunctor, typename ResultType>
|
||||
template <bool P1, typename BinaryOperator, typename ResultType>
|
||||
struct UseKokkosReduceP1 : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename BinaryFunctor, typename ResultType>
|
||||
struct UseKokkosReduceP1<true, BinaryFunctor, ResultType>
|
||||
template <typename BinaryOperator, typename ResultType>
|
||||
struct UseKokkosReduceP1<true, BinaryOperator, ResultType>
|
||||
: vtkm::internal::is_type_complete<
|
||||
kokkos::internal::ReductionIdentity<BinaryFunctor, ResultType>>
|
||||
kokkos::internal::ReductionIdentity<BinaryOperator, ResultType>>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename BinaryFunctor, typename ResultType>
|
||||
template <typename BinaryOperator, typename ResultType>
|
||||
struct UseKokkosReduce
|
||||
: UseKokkosReduceP1<
|
||||
vtkm::internal::is_type_complete<Kokkos::reduction_identity<ResultType>>::value,
|
||||
BinaryFunctor,
|
||||
BinaryOperator,
|
||||
ResultType>
|
||||
{
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename T, typename U, class CIn, class BinaryFunctor>
|
||||
template <typename T, typename U, class CIn, class BinaryOperator>
|
||||
VTKM_CONT static U Reduce(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
U initialValue,
|
||||
BinaryFunctor binary_functor)
|
||||
BinaryOperator binaryOperator)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
if (input.GetNumberOfValues() == 0)
|
||||
{
|
||||
return initialValue;
|
||||
}
|
||||
if (input.GetNumberOfValues() == 1)
|
||||
{
|
||||
return binaryOperator(initialValue, input.ReadPortal().Get(0));
|
||||
}
|
||||
|
||||
#if defined(VTKM_KOKKOS_CUDA)
|
||||
// Kokkos reduce is having some issues with the cuda backend. Please refer to issue #586.
|
||||
// Following is a work around where we use the Superclass reduce implementation when using
|
||||
@ -331,21 +381,276 @@ public:
|
||||
std::integral_constant<
|
||||
bool,
|
||||
!std::is_same<vtkm::cont::kokkos::internal::ExecutionSpace, Kokkos::Cuda>::value &&
|
||||
UseKokkosReduce<BinaryFunctor, U>::value>
|
||||
UseKokkosReduce<BinaryOperator, U>::value>
|
||||
use_kokkos_reduce;
|
||||
#else
|
||||
typename UseKokkosReduce<BinaryFunctor, U>::type use_kokkos_reduce;
|
||||
typename UseKokkosReduce<BinaryOperator, U>::type use_kokkos_reduce;
|
||||
#endif
|
||||
|
||||
return ReduceImpl(input, binary_functor, initialValue, use_kokkos_reduce);
|
||||
return ReduceImpl(input, binaryOperator, initialValue, use_kokkos_reduce);
|
||||
}
|
||||
|
||||
template <typename T, typename U, class CIn>
|
||||
VTKM_CONT static U Reduce(const vtkm::cont::ArrayHandle<T, CIn>& input, U initialValue)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
return Reduce(input, initialValue, vtkm::Add());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
private:
|
||||
// Scan and Reduce have the same conditions
|
||||
template <typename BinaryOperator, typename ResultType>
|
||||
using UseKokkosScan = UseKokkosReduce<BinaryOperator, ResultType>;
|
||||
|
||||
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
|
||||
VTKM_CONT static T ScanExclusiveImpl(const vtkm::cont::ArrayHandle<T, StorageIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, StorageOut>& output,
|
||||
BinaryOperator binaryOperator,
|
||||
const T& initialValue,
|
||||
std::false_type)
|
||||
{
|
||||
return Superclass::ScanExclusive(input, output, binaryOperator, initialValue);
|
||||
}
|
||||
|
||||
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
|
||||
class ScanExclusiveOperator
|
||||
{
|
||||
private:
|
||||
using ArrayPortalIn =
|
||||
typename ArrayHandle<T,
|
||||
StorageIn>::template ExecutionTypes<DeviceAdapterTagKokkos>::PortalConst;
|
||||
using ArrayPortalOut =
|
||||
typename ArrayHandle<T, StorageOut>::template ExecutionTypes<DeviceAdapterTagKokkos>::Portal;
|
||||
|
||||
public:
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
ScanExclusiveOperator() {}
|
||||
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
explicit ScanExclusiveOperator(const ArrayPortalIn& portalIn,
|
||||
const ArrayPortalOut& portalOut,
|
||||
const T& initialValue)
|
||||
: PortalIn(portalIn)
|
||||
, PortalOut(portalOut)
|
||||
, InitialValue(initialValue)
|
||||
{
|
||||
}
|
||||
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
void operator()(const BinaryOperator& op, const vtkm::Id i, T& update, const bool final) const
|
||||
{
|
||||
auto val = this->PortalIn.Get(i);
|
||||
if (i == 0)
|
||||
{
|
||||
update = InitialValue;
|
||||
}
|
||||
if (final)
|
||||
{
|
||||
this->PortalOut.Set(i, update);
|
||||
}
|
||||
update = op(update, val);
|
||||
}
|
||||
|
||||
private:
|
||||
ArrayPortalIn PortalIn;
|
||||
ArrayPortalOut PortalOut;
|
||||
T InitialValue;
|
||||
};
|
||||
|
||||
template <typename BinaryOperator, typename T, typename StorageIn, typename StorageOut>
|
||||
using ScanExclusiveFunctor =
|
||||
KokkosReduceFunctor<BinaryOperator,
|
||||
ScanExclusiveOperator<T, StorageIn, StorageOut, BinaryOperator>,
|
||||
T>;
|
||||
|
||||
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
|
||||
VTKM_CONT static T ScanExclusiveImpl(const vtkm::cont::ArrayHandle<T, StorageIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, StorageOut>& output,
|
||||
BinaryOperator binaryOperator,
|
||||
const T& initialValue,
|
||||
std::true_type)
|
||||
{
|
||||
vtkm::Id length = input.GetNumberOfValues();
|
||||
|
||||
vtkm::cont::Token token;
|
||||
auto inputPortal = input.PrepareForInput(vtkm::cont::DeviceAdapterTagKokkos{}, token);
|
||||
auto outputPortal =
|
||||
output.PrepareForOutput(length, vtkm::cont::DeviceAdapterTagKokkos{}, token);
|
||||
|
||||
ScanExclusiveFunctor<BinaryOperator, T, StorageIn, StorageOut> functor(
|
||||
binaryOperator, inputPortal, outputPortal, initialValue);
|
||||
|
||||
T result = vtkm::TypeTraits<T>::ZeroInitialization();
|
||||
Kokkos::RangePolicy<vtkm::cont::kokkos::internal::ExecutionSpace, vtkm::Id> policy(
|
||||
vtkm::cont::kokkos::internal::GetExecutionSpaceInstance(), 0, length);
|
||||
Kokkos::parallel_scan(policy, functor, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename T, class CIn, class COut, class BinaryOperator>
|
||||
VTKM_CONT static T ScanExclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output,
|
||||
BinaryOperator binaryOperator,
|
||||
const T& initialValue)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
vtkm::Id length = input.GetNumberOfValues();
|
||||
if (length == 0)
|
||||
{
|
||||
output.Shrink(0);
|
||||
return initialValue;
|
||||
}
|
||||
if (length == 1)
|
||||
{
|
||||
auto v0 = input.ReadPortal().Get(0);
|
||||
Fill(output, initialValue, 1);
|
||||
return binaryOperator(initialValue, v0);
|
||||
}
|
||||
|
||||
#if defined(VTKM_KOKKOS_CUDA)
|
||||
// Kokkos scan for the cuda backend is not working correctly for int/uint types of 8 and 16 bits.
|
||||
std::integral_constant<bool,
|
||||
!(std::is_integral<T>::value && sizeof(T) < 4) &&
|
||||
UseKokkosScan<BinaryOperator, T>::value>
|
||||
use_kokkos_scan;
|
||||
#else
|
||||
typename UseKokkosScan<BinaryOperator, T>::type use_kokkos_scan;
|
||||
#endif
|
||||
return ScanExclusiveImpl(input, output, binaryOperator, initialValue, use_kokkos_scan);
|
||||
}
|
||||
|
||||
template <typename T, class CIn, class COut>
|
||||
VTKM_CONT static T ScanExclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
return ScanExclusive(input, output, vtkm::Sum(), vtkm::TypeTraits<T>::ZeroInitialization());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
private:
|
||||
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
|
||||
VTKM_CONT static T ScanInclusiveImpl(const vtkm::cont::ArrayHandle<T, StorageIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, StorageOut>& output,
|
||||
BinaryOperator binaryOperator,
|
||||
std::false_type)
|
||||
{
|
||||
return Superclass::ScanInclusive(input, output, binaryOperator);
|
||||
}
|
||||
|
||||
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
|
||||
class ScanInclusiveOperator
|
||||
{
|
||||
private:
|
||||
using ArrayPortalIn =
|
||||
typename ArrayHandle<T,
|
||||
StorageIn>::template ExecutionTypes<DeviceAdapterTagKokkos>::PortalConst;
|
||||
using ArrayPortalOut =
|
||||
typename ArrayHandle<T, StorageOut>::template ExecutionTypes<DeviceAdapterTagKokkos>::Portal;
|
||||
|
||||
public:
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
ScanInclusiveOperator() {}
|
||||
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
explicit ScanInclusiveOperator(const ArrayPortalIn& portalIn, const ArrayPortalOut& portalOut)
|
||||
: PortalIn(portalIn)
|
||||
, PortalOut(portalOut)
|
||||
{
|
||||
}
|
||||
|
||||
KOKKOS_INLINE_FUNCTION
|
||||
void operator()(const BinaryOperator& op, const vtkm::Id i, T& update, const bool final) const
|
||||
{
|
||||
update = op(update, this->PortalIn.Get(i));
|
||||
if (final)
|
||||
{
|
||||
this->PortalOut.Set(i, update);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ArrayPortalIn PortalIn;
|
||||
ArrayPortalOut PortalOut;
|
||||
};
|
||||
|
||||
template <typename BinaryOperator, typename T, typename StorageIn, typename StorageOut>
|
||||
using ScanInclusiveFunctor =
|
||||
KokkosReduceFunctor<BinaryOperator,
|
||||
ScanInclusiveOperator<T, StorageIn, StorageOut, BinaryOperator>,
|
||||
T>;
|
||||
|
||||
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
|
||||
VTKM_CONT static T ScanInclusiveImpl(const vtkm::cont::ArrayHandle<T, StorageIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, StorageOut>& output,
|
||||
BinaryOperator binaryOperator,
|
||||
std::true_type)
|
||||
{
|
||||
vtkm::Id length = input.GetNumberOfValues();
|
||||
|
||||
vtkm::cont::Token token;
|
||||
auto inputPortal = input.PrepareForInput(vtkm::cont::DeviceAdapterTagKokkos{}, token);
|
||||
auto outputPortal =
|
||||
output.PrepareForOutput(length, vtkm::cont::DeviceAdapterTagKokkos{}, token);
|
||||
|
||||
ScanInclusiveFunctor<BinaryOperator, T, StorageIn, StorageOut> functor(
|
||||
binaryOperator, inputPortal, outputPortal);
|
||||
|
||||
T result = vtkm::TypeTraits<T>::ZeroInitialization();
|
||||
Kokkos::RangePolicy<vtkm::cont::kokkos::internal::ExecutionSpace, vtkm::Id> policy(
|
||||
vtkm::cont::kokkos::internal::GetExecutionSpaceInstance(), 0, length);
|
||||
Kokkos::parallel_scan(policy, functor, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename T, class CIn, class COut, class BinaryOperator>
|
||||
VTKM_CONT static T ScanInclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output,
|
||||
BinaryOperator binaryOperator)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
vtkm::Id length = input.GetNumberOfValues();
|
||||
if (length == 0)
|
||||
{
|
||||
return vtkm::TypeTraits<T>::ZeroInitialization();
|
||||
}
|
||||
if (length == 1)
|
||||
{
|
||||
auto result = input.ReadPortal().Get(0);
|
||||
Fill(output, result, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(VTKM_KOKKOS_CUDA)
|
||||
// Kokkos scan for the cuda backend is not working correctly for int/uint types of 8 and 16 bits.
|
||||
std::integral_constant<bool,
|
||||
!(std::is_integral<T>::value && sizeof(T) < 4) &&
|
||||
UseKokkosScan<BinaryOperator, T>::value>
|
||||
use_kokkos_scan;
|
||||
#else
|
||||
typename UseKokkosScan<BinaryOperator, T>::type use_kokkos_scan;
|
||||
#endif
|
||||
return ScanInclusiveImpl(input, output, binaryOperator, use_kokkos_scan);
|
||||
}
|
||||
|
||||
template <typename T, class CIn, class COut>
|
||||
VTKM_CONT static T ScanInclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
return ScanInclusive(input, output, vtkm::Add());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
template <typename WType, typename IType>
|
||||
VTKM_CONT static void ScheduleTask(
|
||||
vtkm::exec::kokkos::internal::TaskBasic1D<WType, IType>& functor,
|
||||
@ -415,6 +720,7 @@ public:
|
||||
ScheduleTask(kernel, rangeMax);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
private:
|
||||
template <typename T>
|
||||
VTKM_CONT static void SortImpl(vtkm::cont::ArrayHandle<T>& values, vtkm::SortLess, std::true_type)
|
||||
@ -456,6 +762,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
template <>
|
||||
class DeviceTaskTypes<vtkm::cont::DeviceAdapterTagKokkos>
|
||||
{
|
||||
|
@ -36,6 +36,7 @@ set(unit_tests
|
||||
UnitTestArrayGetValues.cxx
|
||||
UnitTestArrayHandleCartesianProduct.cxx
|
||||
UnitTestArrayHandleCompositeVector.cxx
|
||||
UnitTestArrayHandleConcatenate.cxx
|
||||
UnitTestArrayHandleCounting.cxx
|
||||
UnitTestArrayHandleDecorator.cxx
|
||||
UnitTestArrayHandleDiscard.cxx
|
||||
@ -52,7 +53,6 @@ set(unit_tests
|
||||
UnitTestArrayHandleThreadSafety.cxx
|
||||
UnitTestArrayHandleTransform.cxx
|
||||
UnitTestArrayHandleUniformPointCoordinates.cxx
|
||||
UnitTestArrayHandleConcatenate.cxx
|
||||
UnitTestArrayHandleVirtual.cxx
|
||||
UnitTestArrayPortalToIterators.cxx
|
||||
UnitTestCellLocatorGeneral.cxx
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <vtkm/cont/RuntimeDeviceInformation.h>
|
||||
#include <vtkm/cont/Timer.h>
|
||||
|
||||
#include <vtkm/cont/internal/ArrayPortalFromIterators.h>
|
||||
#include <vtkm/cont/internal/VirtualObjectTransfer.h>
|
||||
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/ArrayHandleMultiplexer.h>
|
||||
#include <vtkm/cont/ArrayHandlePermutation.h>
|
||||
#include <vtkm/cont/ArrayHandleRecombineVec.h>
|
||||
#include <vtkm/cont/ArrayHandleSOA.h>
|
||||
#include <vtkm/cont/ArrayHandleTransform.h>
|
||||
#include <vtkm/cont/ArrayHandleView.h>
|
||||
@ -222,12 +223,12 @@ public:
|
||||
struct PassThrough : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
using ControlSignature = void(FieldIn, FieldOut);
|
||||
using ExecutionSignature = _2(_1);
|
||||
using ExecutionSignature = void(_1, _2);
|
||||
|
||||
template <class ValueType>
|
||||
VTKM_EXEC ValueType operator()(const ValueType& inValue) const
|
||||
template <typename InValue, typename OutValue>
|
||||
VTKM_EXEC void operator()(const InValue& inValue, OutValue& outValue) const
|
||||
{
|
||||
return inValue;
|
||||
outValue = inValue;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1154,6 +1155,61 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
struct TestRecombineVecAsInput
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T> baseArray;
|
||||
baseArray.Allocate(ARRAY_SIZE);
|
||||
SetPortal(baseArray.WritePortal());
|
||||
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
vtkm::cont::ArrayHandleRecombineVec<typename VTraits::ComponentType> recombinedArray;
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < VTraits::NUM_COMPONENTS; ++cIndex)
|
||||
{
|
||||
recombinedArray.AppendComponentArray(vtkm::cont::ArrayExtractComponent(baseArray, cIndex));
|
||||
}
|
||||
VTKM_TEST_ASSERT(recombinedArray.GetNumberOfComponents() == VTraits::NUM_COMPONENTS);
|
||||
VTKM_TEST_ASSERT(recombinedArray.GetNumberOfValues() == ARRAY_SIZE);
|
||||
|
||||
vtkm::cont::ArrayHandle<T> outputArray;
|
||||
vtkm::cont::Invoker invoke;
|
||||
invoke(PassThrough{}, recombinedArray, outputArray);
|
||||
|
||||
VTKM_TEST_ASSERT(test_equal_ArrayHandles(baseArray, outputArray));
|
||||
}
|
||||
};
|
||||
|
||||
struct TestRecombineVecAsOutput
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T> baseArray;
|
||||
baseArray.Allocate(ARRAY_SIZE);
|
||||
SetPortal(baseArray.WritePortal());
|
||||
|
||||
vtkm::cont::ArrayHandle<T> outputArray;
|
||||
outputArray.Allocate(ARRAY_SIZE); // Cannot resize after recombine
|
||||
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
vtkm::cont::ArrayHandleRecombineVec<typename VTraits::ComponentType> recombinedArray;
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < VTraits::NUM_COMPONENTS; ++cIndex)
|
||||
{
|
||||
recombinedArray.AppendComponentArray(
|
||||
vtkm::cont::ArrayExtractComponent(outputArray, cIndex));
|
||||
}
|
||||
VTKM_TEST_ASSERT(recombinedArray.GetNumberOfComponents() == VTraits::NUM_COMPONENTS);
|
||||
VTKM_TEST_ASSERT(recombinedArray.GetNumberOfValues() == ARRAY_SIZE);
|
||||
|
||||
vtkm::cont::Invoker invoke;
|
||||
invoke(PassThrough{}, baseArray, recombinedArray);
|
||||
|
||||
VTKM_TEST_ASSERT(test_equal_ArrayHandles(baseArray, outputArray));
|
||||
}
|
||||
};
|
||||
|
||||
struct TestZipAsInput
|
||||
{
|
||||
template <typename KeyType, typename ValueType>
|
||||
@ -1426,6 +1482,8 @@ private:
|
||||
|
||||
using ScalarTypesToTest = vtkm::List<vtkm::UInt8, vtkm::FloatDefault>;
|
||||
|
||||
using VectorTypesToTest = vtkm::List<vtkm::Vec2i_8, vtkm::Vec3f_32>;
|
||||
|
||||
using ZipTypesToTest = vtkm::List<vtkm::Pair<vtkm::UInt8, vtkm::Id>,
|
||||
vtkm::Pair<vtkm::Float64, vtkm::Vec4ui_8>,
|
||||
vtkm::Pair<vtkm::Vec3f_32, vtkm::Vec4i_8>>;
|
||||
@ -1449,12 +1507,12 @@ private:
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleSOA as Input" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(TestingFancyArrayHandles<DeviceAdapterTag>::TestSOAAsInput(),
|
||||
HandleTypesToTest());
|
||||
VectorTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleSOA as Output" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(
|
||||
TestingFancyArrayHandles<DeviceAdapterTag>::TestSOAAsOutput(), HandleTypesToTest());
|
||||
TestingFancyArrayHandles<DeviceAdapterTag>::TestSOAAsOutput(), VectorTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleCompositeVector as Input" << std::endl;
|
||||
@ -1555,6 +1613,17 @@ private:
|
||||
TestingFancyArrayHandles<DeviceAdapterTag>::TestGroupVecVariableAsOutput(),
|
||||
ScalarTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleRecombineVec as Input" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(
|
||||
TestingFancyArrayHandles<DeviceAdapterTag>::TestRecombineVecAsInput(), HandleTypesToTest{});
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleRecombineVec as Output" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(
|
||||
TestingFancyArrayHandles<DeviceAdapterTag>::TestRecombineVecAsOutput(),
|
||||
HandleTypesToTest{});
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleZip as Input" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(TestingFancyArrayHandles<DeviceAdapterTag>::TestZipAsInput(),
|
||||
|
@ -378,7 +378,7 @@ void TestArrayHandleSerialization()
|
||||
TestArrayHandleBasic(), vtkm::List<char, long, long long, unsigned long, unsigned long long>());
|
||||
|
||||
std::cout << "Testing ArrayHandleSOA\n";
|
||||
vtkm::testing::Testing::TryTypes(TestArrayHandleSOA(), TestTypesList());
|
||||
vtkm::testing::Testing::TryTypes(TestArrayHandleSOA(), TestTypesListVec());
|
||||
|
||||
std::cout << "Testing ArrayHandleCartesianProduct\n";
|
||||
vtkm::testing::Testing::TryTypes(TestArrayHandleCartesianProduct(), TestTypesListScalar());
|
||||
|
@ -428,6 +428,26 @@ void TryAsArrayHandle()
|
||||
TryAsArrayHandle(vtkm::cont::make_ArrayHandleConstant(5, ARRAY_SIZE));
|
||||
}
|
||||
|
||||
struct CheckExtractedArray
|
||||
{
|
||||
template <typename ExtractedArray, typename OriginalArray>
|
||||
void operator()(const ExtractedArray& extractedArray, const OriginalArray& originalArray) const
|
||||
{
|
||||
using ValueType = typename OriginalArray::ValueType;
|
||||
using FlatVec = vtkm::VecFlat<ValueType>;
|
||||
|
||||
VTKM_TEST_ASSERT(extractedArray.GetNumberOfComponents() == FlatVec::NUM_COMPONENTS);
|
||||
auto originalPortal = originalArray.ReadPortal();
|
||||
auto extractedPortal = extractedArray.ReadPortal();
|
||||
for (vtkm::Id valueIndex = 0; valueIndex < ARRAY_SIZE; ++valueIndex)
|
||||
{
|
||||
FlatVec originalData = originalPortal.Get(valueIndex);
|
||||
auto extractedData = extractedPortal.Get(valueIndex);
|
||||
VTKM_TEST_ASSERT(test_equal(originalData, extractedData));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ArrayHandleType>
|
||||
void TryExtractComponent()
|
||||
{
|
||||
@ -443,15 +463,9 @@ void TryExtractComponent()
|
||||
|
||||
VTKM_TEST_ASSERT(unknownArray.GetNumberOfComponentsFlat() == FlatVec::NUM_COMPONENTS);
|
||||
|
||||
auto componentPortal = unknownArray.ReadPortalForBaseComponentType<ComponentType>();
|
||||
CheckExtractedArray{}(unknownArray.ExtractArrayFromComponents<ComponentType>(), originalArray);
|
||||
|
||||
auto originalPortal = originalArray.ReadPortal();
|
||||
for (vtkm::Id valueIndex = 0; valueIndex < ARRAY_SIZE; ++valueIndex)
|
||||
{
|
||||
FlatVec originalData = originalPortal.Get(valueIndex);
|
||||
auto componentData = componentPortal.Get(valueIndex);
|
||||
VTKM_TEST_ASSERT(test_equal(originalData, componentData));
|
||||
}
|
||||
unknownArray.CastAndCallWithExtractedArray(CheckExtractedArray{}, originalArray);
|
||||
}
|
||||
|
||||
void TryExtractComponent()
|
||||
@ -459,6 +473,9 @@ void TryExtractComponent()
|
||||
std::cout << " Scalar array." << std::endl;
|
||||
TryExtractComponent<vtkm::cont::ArrayHandle<vtkm::FloatDefault>>();
|
||||
|
||||
std::cout << " Equivalent scalar." << std::endl;
|
||||
TryExtractComponent<vtkm::cont::ArrayHandle<VTKM_UNUSED_INT_TYPE>>();
|
||||
|
||||
std::cout << " Basic Vec." << std::endl;
|
||||
TryExtractComponent<vtkm::cont::ArrayHandle<vtkm::Id3>>();
|
||||
|
||||
|
@ -416,17 +416,20 @@ void TryAsMultiplexer(T, ArrayVariantType sourceArray)
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TryDefaultType(T)
|
||||
struct TryDefaultType
|
||||
{
|
||||
vtkm::cont::VariantArrayHandle array = CreateArrayVariant(T());
|
||||
template <typename T>
|
||||
void operator()(T) const
|
||||
{
|
||||
vtkm::cont::VariantArrayHandle array = CreateArrayVariant(T());
|
||||
|
||||
CheckArrayVariant(array, vtkm::VecTraits<T>::NUM_COMPONENTS, true);
|
||||
CheckArrayVariant(array, vtkm::VecTraits<T>::NUM_COMPONENTS, true);
|
||||
|
||||
TryNewInstance(T(), array);
|
||||
TryNewInstance(T(), array);
|
||||
|
||||
TryAsMultiplexer(T(), array);
|
||||
}
|
||||
TryAsMultiplexer(T(), array);
|
||||
}
|
||||
};
|
||||
|
||||
struct TryBasicVTKmType
|
||||
{
|
||||
@ -471,18 +474,18 @@ void TryCastToArrayHandle(const ArrayHandleType& array)
|
||||
void TryCastToArrayHandle()
|
||||
{
|
||||
std::cout << " Normal array handle." << std::endl;
|
||||
vtkm::Id buffer[ARRAY_SIZE];
|
||||
vtkm::FloatDefault buffer[ARRAY_SIZE];
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
|
||||
{
|
||||
buffer[index] = TestValue(index, vtkm::Id());
|
||||
buffer[index] = TestValue(index, vtkm::FloatDefault());
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> array =
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array =
|
||||
vtkm::cont::make_ArrayHandle(buffer, ARRAY_SIZE, vtkm::CopyFlag::On);
|
||||
TryCastToArrayHandle(array);
|
||||
|
||||
std::cout << " Cast array handle." << std::endl;
|
||||
TryCastToArrayHandle(vtkm::cont::make_ArrayHandleCast(array, vtkm::FloatDefault()));
|
||||
TryCastToArrayHandle(vtkm::cont::make_ArrayHandleCast<vtkm::Id>(array));
|
||||
|
||||
std::cout << " Composite vector array handle." << std::endl;
|
||||
TryCastToArrayHandle(vtkm::cont::make_ArrayHandleCompositeVector(array, array));
|
||||
@ -495,7 +498,8 @@ void TryCastToArrayHandle()
|
||||
TryCastToArrayHandle(countingArray);
|
||||
|
||||
std::cout << " Group vec array handle" << std::endl;
|
||||
vtkm::cont::ArrayHandleGroupVec<vtkm::cont::ArrayHandle<vtkm::Id>, 2> groupVecArray(array);
|
||||
vtkm::cont::ArrayHandleGroupVec<vtkm::cont::ArrayHandle<vtkm::FloatDefault>, 2> groupVecArray(
|
||||
array);
|
||||
TryCastToArrayHandle(groupVecArray);
|
||||
|
||||
std::cout << " Implicit array handle." << std::endl;
|
||||
@ -522,18 +526,7 @@ void TryCastToArrayHandle()
|
||||
void TestVariantArrayHandle()
|
||||
{
|
||||
std::cout << "Try common types with default type lists." << std::endl;
|
||||
std::cout << "*** vtkm::Id **********************" << std::endl;
|
||||
TryDefaultType(vtkm::Id());
|
||||
std::cout << "*** vtkm::FloatDefault ************" << std::endl;
|
||||
TryDefaultType(vtkm::FloatDefault());
|
||||
std::cout << "*** vtkm::Float32 *****************" << std::endl;
|
||||
TryDefaultType(vtkm::Float32());
|
||||
std::cout << "*** vtkm::Float64 *****************" << std::endl;
|
||||
TryDefaultType(vtkm::Float64());
|
||||
std::cout << "*** vtkm::Vec<Float32,3> **********" << std::endl;
|
||||
TryDefaultType(vtkm::Vec3f_32());
|
||||
std::cout << "*** vtkm::Vec<Float64,3> **********" << std::endl;
|
||||
TryDefaultType(vtkm::Vec3f_64());
|
||||
vtkm::testing::Testing::TryTypes(TryDefaultType{}, VTKM_DEFAULT_TYPE_LIST{});
|
||||
|
||||
std::cout << "Try exemplar VTK-m types." << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(TryBasicVTKmType());
|
||||
|
@ -172,14 +172,15 @@ public:
|
||||
/// This operation is typically used in a loop. For example usage,
|
||||
/// an atomic multiplication may be implemented using compare-exchange as follows:
|
||||
///
|
||||
/// ```
|
||||
/// AtomicArrayExecutionObject<vtkm::Int32, ...> arr = ...;
|
||||
/// ```cpp
|
||||
/// AtomicArrayExecutionObject<vtkm::Int32, ...> atomicArray = ...;
|
||||
///
|
||||
/// // Compare-exchange multiplication:
|
||||
/// vtkm::Int32 current = arr->Get(idx); // Load the current value at idx
|
||||
/// vtkm::Int32 current = atomicArray.Get(idx); // Load the current value at idx
|
||||
/// vtkm::Int32 newVal;
|
||||
/// do {
|
||||
/// vtkm::Int32 newVal = current * multFactor; // the actual multiplication
|
||||
/// } while (!arr->CompareExchange(idx, ¤t, newVal));
|
||||
/// newVal = current * multFactor; // the actual multiplication
|
||||
/// } while (!atomicArray.CompareExchange(idx, ¤t, newVal));
|
||||
/// ```
|
||||
///
|
||||
/// The while condition here updates \a newVal what the proper multiplication
|
||||
@ -191,6 +192,15 @@ public:
|
||||
/// loop body re-executes using the new value of \a current and tries again until
|
||||
/// it succeeds.
|
||||
///
|
||||
/// Note that for demonstration purposes, the previous code is unnecessarily verbose.
|
||||
/// We can express the same atomic operation more succinctly with just two lines where
|
||||
/// \a newVal is just computed in place.
|
||||
///
|
||||
/// ```cpp
|
||||
/// vtkm::Int32 current = atomicArray.Get(idx); // Load the current value at idx
|
||||
/// while (!atomicArray.CompareExchange(idx, ¤t, current * multFactor));
|
||||
/// ```
|
||||
///
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
VTKM_EXEC
|
||||
bool CompareExchange(vtkm::Id index, ValueType* oldValue, const ValueType& newValue) const
|
||||
|
@ -19,6 +19,8 @@ set(headers
|
||||
FetchTagArrayDirectIn.h
|
||||
FetchTagArrayDirectInOut.h
|
||||
FetchTagArrayDirectOut.h
|
||||
FetchTagArrayDirectOutArrayHandleGroupVecVariable.h
|
||||
FetchTagArrayDirectOutArrayHandleRecombineVec.h
|
||||
FetchTagArrayNeighborhoodIn.h
|
||||
FetchTagArrayTopologyMapIn.h
|
||||
FetchTagExecObject.h
|
||||
|
@ -0,0 +1,69 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleGroupVecVariable_h
|
||||
#define vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleGroupVecVariable_h
|
||||
|
||||
#include <vtkm/exec/arg/FetchTagArrayDirectOut.h>
|
||||
|
||||
// We need to override the fetch for output fields using
|
||||
// ArrayPortalGroupVecVariable because this portal does not behave like most
|
||||
// ArrayPortals. Usually you ignore the Load and implement the Store. But if
|
||||
// you ignore the Load, the VecFromPortal gets no portal to set values into.
|
||||
// Instead, you need to implement the Load to point to the array portal. You
|
||||
// can also ignore the Store because the data is already set in the array at
|
||||
// that point.
|
||||
|
||||
// This file is included from ArrayHandleGroupVecVariable.h
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace exec
|
||||
{
|
||||
namespace arg
|
||||
{
|
||||
|
||||
// We need to override the fetch for output fields using
|
||||
// ArrayPortalGroupVecVariable because this portal does not behave like most
|
||||
// ArrayPortals. Usually you ignore the Load and implement the Store. But if
|
||||
// you ignore the Load, the VecFromPortal gets no portal to set values into.
|
||||
// Instead, you need to implement the Load to point to the array portal. You
|
||||
// can also ignore the Store because the data is already set in the array at
|
||||
// that point.
|
||||
template <typename ComponentsPortalType, typename OffsetsPortalType>
|
||||
struct Fetch<vtkm::exec::arg::FetchTagArrayDirectOut,
|
||||
vtkm::exec::arg::AspectTagDefault,
|
||||
vtkm::internal::ArrayPortalGroupVecVariable<ComponentsPortalType, OffsetsPortalType>>
|
||||
{
|
||||
using ExecObjectType =
|
||||
vtkm::internal::ArrayPortalGroupVecVariable<ComponentsPortalType, OffsetsPortalType>;
|
||||
using ValueType = typename ExecObjectType::ValueType;
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
template <typename ThreadIndicesType>
|
||||
VTKM_EXEC ValueType Load(const ThreadIndicesType& indices,
|
||||
const ExecObjectType& arrayPortal) const
|
||||
{
|
||||
return arrayPortal.Get(indices.GetOutputIndex());
|
||||
}
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
template <typename ThreadIndicesType>
|
||||
VTKM_EXEC void Store(const ThreadIndicesType&, const ExecObjectType&, const ValueType&) const
|
||||
{
|
||||
// We can actually ignore this because the VecFromPortal will already have
|
||||
// set new values in the array.
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::exec::arg
|
||||
|
||||
#endif //vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleGroupVecVariable_h
|
@ -0,0 +1,46 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleRecombineVec_h
|
||||
#define vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleRecombineVec_h
|
||||
|
||||
#include <vtkm/exec/arg/FetchTagArrayDirectInOut.h>
|
||||
#include <vtkm/exec/arg/FetchTagArrayDirectOut.h>
|
||||
|
||||
// The `Fetch` for direct array out breaks for `ArrayHandleRecombineVec` because the `Load`
|
||||
// method attempts to create a `vtkm::internal::RecombineVec` with a default constructor,
|
||||
// which does not exist. Instead, have the direct out `Fetch` behave like the direct in/out
|
||||
// `Fetch`, which loads the initial value from the array. The actual load will not load the
|
||||
// data but rather set up the portals in the returned object, which is necessary for the
|
||||
// later `Store` to work anyway.
|
||||
|
||||
// This file is included from ArrayHandleRecombineVec.h
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace exec
|
||||
{
|
||||
namespace arg
|
||||
{
|
||||
|
||||
template <typename SourcePortalType>
|
||||
struct Fetch<vtkm::exec::arg::FetchTagArrayDirectOut,
|
||||
vtkm::exec::arg::AspectTagDefault,
|
||||
vtkm::internal::ArrayPortalRecombineVec<SourcePortalType>>
|
||||
: Fetch<vtkm::exec::arg::FetchTagArrayDirectInOut,
|
||||
vtkm::exec::arg::AspectTagDefault,
|
||||
vtkm::internal::ArrayPortalRecombineVec<SourcePortalType>>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::exec::arg
|
||||
|
||||
#endif //vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleRecombineVec_h
|
@ -149,6 +149,12 @@ extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradien
|
||||
const vtkm::filter::FieldMetadata&,
|
||||
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
|
||||
|
||||
extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
|
||||
const vtkm::cont::DataSet&,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Vec3f_32, vtkm::cont::StorageTagSOA>&,
|
||||
const vtkm::filter::FieldMetadata&,
|
||||
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
|
||||
|
||||
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
|
||||
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
||||
extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
|
||||
@ -165,6 +171,12 @@ extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradien
|
||||
const vtkm::filter::FieldMetadata&,
|
||||
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
|
||||
|
||||
extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
|
||||
const vtkm::cont::DataSet&,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Vec3f_64, vtkm::cont::StorageTagSOA>&,
|
||||
const vtkm::filter::FieldMetadata&,
|
||||
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
|
||||
|
||||
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
|
||||
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
||||
extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
|
||||
|
@ -24,6 +24,12 @@ template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
|
||||
const vtkm::filter::FieldMetadata&,
|
||||
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
|
||||
|
||||
template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
|
||||
const vtkm::cont::DataSet&,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Vec3f_32, vtkm::cont::StorageTagSOA>&,
|
||||
const vtkm::filter::FieldMetadata&,
|
||||
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
|
||||
|
||||
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
|
||||
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
||||
template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
|
||||
@ -40,6 +46,12 @@ template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
|
||||
const vtkm::filter::FieldMetadata&,
|
||||
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
|
||||
|
||||
template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
|
||||
const vtkm::cont::DataSet&,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Vec3f_64, vtkm::cont::StorageTagSOA>&,
|
||||
const vtkm::filter::FieldMetadata&,
|
||||
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
|
||||
|
||||
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
|
||||
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
||||
template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
|
||||
|
@ -35,16 +35,31 @@ public:
|
||||
|
||||
VTKM_CONT ImageDifference();
|
||||
|
||||
VTKM_CONT vtkm::IdComponent GetRadius() const { return this->Radius; }
|
||||
VTKM_CONT void SetRadius(const vtkm::IdComponent& radius) { this->Radius = radius; }
|
||||
|
||||
VTKM_CONT vtkm::FloatDefault GetThreshold() const { return this->Threshold; }
|
||||
VTKM_CONT void SetThreshold(const vtkm::FloatDefault& threshold) { this->Threshold = threshold; }
|
||||
|
||||
VTKM_CONT bool GetAveragePixels() const { return this->AveragePixels; }
|
||||
VTKM_CONT void SetAveragePixels(const bool& averagePixels)
|
||||
VTKM_CONT vtkm::IdComponent GetAverageRadius() const { return this->AverageRadius; }
|
||||
VTKM_CONT void SetAverageRadius(const vtkm::IdComponent& averageRadius)
|
||||
{
|
||||
this->AveragePixels = averagePixels;
|
||||
this->AverageRadius = averageRadius;
|
||||
}
|
||||
|
||||
VTKM_CONT vtkm::IdComponent GetPixelShiftRadius() const { return this->PixelShiftRadius; }
|
||||
VTKM_CONT void SetPixelShiftRadius(const vtkm::IdComponent& pixelShiftRadius)
|
||||
{
|
||||
this->PixelShiftRadius = pixelShiftRadius;
|
||||
}
|
||||
|
||||
VTKM_CONT vtkm::FloatDefault GetAllowedPixelErrorRatio() const
|
||||
{
|
||||
return this->AllowedPixelErrorRatio;
|
||||
}
|
||||
VTKM_CONT void SetAllowedPixelErrorRatio(const vtkm::FloatDefault& pixelErrorRatio)
|
||||
{
|
||||
this->AllowedPixelErrorRatio = pixelErrorRatio;
|
||||
}
|
||||
|
||||
VTKM_CONT vtkm::FloatDefault GetPixelDiffThreshold() const { return this->PixelDiffThreshold; }
|
||||
VTKM_CONT void SetPixelDiffThreshold(const vtkm::FloatDefault& threshold)
|
||||
{
|
||||
this->PixelDiffThreshold = threshold;
|
||||
}
|
||||
|
||||
VTKM_CONT bool GetImageDiffWithinThreshold() const { return this->ImageDiffWithinThreshold; }
|
||||
@ -91,9 +106,10 @@ public:
|
||||
vtkm::filter::PolicyBase<DerivedPolicy> policy);
|
||||
|
||||
private:
|
||||
vtkm::IdComponent Radius;
|
||||
vtkm::FloatDefault Threshold;
|
||||
bool AveragePixels;
|
||||
vtkm::IdComponent AverageRadius;
|
||||
vtkm::IdComponent PixelShiftRadius;
|
||||
vtkm::FloatDefault AllowedPixelErrorRatio;
|
||||
vtkm::FloatDefault PixelDiffThreshold;
|
||||
bool ImageDiffWithinThreshold;
|
||||
std::string SecondaryFieldName;
|
||||
vtkm::cont::Field::Association SecondaryFieldAssociation;
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
#include <vtkm/filter/ImageDifference.h>
|
||||
|
||||
#include <vtkm/BinaryOperators.h>
|
||||
#include <vtkm/cont/Algorithm.h>
|
||||
#include <vtkm/cont/ArrayPortalToIterators.h>
|
||||
#include <vtkm/cont/Logging.h>
|
||||
@ -25,11 +24,25 @@ namespace vtkm
|
||||
namespace filter
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct GreaterThanThreshold
|
||||
{
|
||||
GreaterThanThreshold(const vtkm::FloatDefault& thresholdError)
|
||||
: ThresholdError(thresholdError)
|
||||
{
|
||||
}
|
||||
VTKM_EXEC_CONT bool operator()(const vtkm::FloatDefault& x) const { return x > ThresholdError; }
|
||||
vtkm::FloatDefault ThresholdError;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
inline VTKM_CONT ImageDifference::ImageDifference()
|
||||
: vtkm::filter::FilterField<ImageDifference>()
|
||||
, Radius(0)
|
||||
, Threshold(0.05f)
|
||||
, AveragePixels(false)
|
||||
, AverageRadius(0)
|
||||
, PixelShiftRadius(0)
|
||||
, AllowedPixelErrorRatio(0.0001f)
|
||||
, PixelDiffThreshold(0.05f)
|
||||
, ImageDiffWithinThreshold(true)
|
||||
, SecondaryFieldName("image-2")
|
||||
, SecondaryFieldAssociation(vtkm::cont::Field::Association::ANY)
|
||||
@ -62,12 +75,13 @@ inline VTKM_CONT vtkm::cont::DataSet ImageDifference::DoExecute(
|
||||
vtkm::cont::ArrayHandle<T, StorageType> diffOutput;
|
||||
vtkm::cont::ArrayHandle<T, StorageType> primaryOutput;
|
||||
vtkm::cont::ArrayHandle<T, StorageType> secondaryOutput;
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault, StorageType> thresholdOutput;
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> thresholdOutput;
|
||||
|
||||
if (this->AveragePixels && this->Radius > 0)
|
||||
if (this->AverageRadius > 0)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Performing Average with radius: " << this->Radius);
|
||||
auto averageWorklet = vtkm::worklet::AveragePointNeighborhood(this->Radius);
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
"Performing Average with radius: " << this->AverageRadius);
|
||||
auto averageWorklet = vtkm::worklet::AveragePointNeighborhood(this->AverageRadius);
|
||||
this->Invoke(averageWorklet, cellSet, primary, primaryOutput);
|
||||
this->Invoke(averageWorklet, cellSet, secondary, secondaryOutput);
|
||||
}
|
||||
@ -79,10 +93,11 @@ inline VTKM_CONT vtkm::cont::DataSet ImageDifference::DoExecute(
|
||||
secondaryField.GetData().template Cast<vtkm::cont::ArrayHandle<T, StorageType>>();
|
||||
}
|
||||
|
||||
if (this->Radius > 0)
|
||||
if (this->PixelShiftRadius > 0)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Diffing image in Neighborhood");
|
||||
auto diffWorklet = vtkm::worklet::ImageDifferenceNeighborhood(this->Radius, this->Threshold);
|
||||
auto diffWorklet =
|
||||
vtkm::worklet::ImageDifferenceNeighborhood(this->PixelShiftRadius, this->PixelDiffThreshold);
|
||||
this->Invoke(diffWorklet, cellSet, primaryOutput, secondaryOutput, diffOutput, thresholdOutput);
|
||||
}
|
||||
else
|
||||
@ -92,17 +107,26 @@ inline VTKM_CONT vtkm::cont::DataSet ImageDifference::DoExecute(
|
||||
this->Invoke(diffWorklet, primaryOutput, secondaryOutput, diffOutput, thresholdOutput);
|
||||
}
|
||||
|
||||
// Dummy calculate the threshold. If any value is greater than the min our images
|
||||
// are not similar enough.
|
||||
vtkm::FloatDefault maxThreshold =
|
||||
vtkm::cont::Algorithm::Reduce(thresholdOutput, vtkm::FloatDefault(0), vtkm::Maximum());
|
||||
if (maxThreshold > this->Threshold)
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault, StorageType> errorPixels;
|
||||
vtkm::cont::Algorithm::CopyIf(thresholdOutput,
|
||||
thresholdOutput,
|
||||
errorPixels,
|
||||
detail::GreaterThanThreshold(this->PixelDiffThreshold));
|
||||
if (errorPixels.GetNumberOfValues() >
|
||||
thresholdOutput.GetNumberOfValues() * this->AllowedPixelErrorRatio)
|
||||
{
|
||||
this->ImageDiffWithinThreshold = false;
|
||||
}
|
||||
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
"Difference within threshold: " << this->ImageDiffWithinThreshold);
|
||||
"Difference within threshold: "
|
||||
<< this->ImageDiffWithinThreshold
|
||||
<< ", for pixels outside threshold: " << errorPixels.GetNumberOfValues()
|
||||
<< ", with total number of pixels: " << thresholdOutput.GetNumberOfValues()
|
||||
<< ", and an allowable percentage of errored pixels: "
|
||||
<< this->AllowedPixelErrorRatio << ", with a total summed threshold error: "
|
||||
<< vtkm::cont::Algorithm::Reduce(errorPixels, static_cast<FloatDefault>(0)));
|
||||
|
||||
vtkm::cont::DataSet clone;
|
||||
clone.CopyStructure(input);
|
||||
|
@ -21,31 +21,15 @@ namespace
|
||||
|
||||
struct DoMapFieldMerge
|
||||
{
|
||||
template <typename BaseComponentType>
|
||||
void operator()(BaseComponentType,
|
||||
const vtkm::cont::UnknownArrayHandle& input,
|
||||
template <typename InputArrayType>
|
||||
void operator()(const InputArrayType& input,
|
||||
const vtkm::worklet::internal::KeysBase& keys,
|
||||
vtkm::cont::UnknownArrayHandle& output,
|
||||
bool& called) const
|
||||
vtkm::cont::UnknownArrayHandle& output) const
|
||||
{
|
||||
if (!input.IsBaseComponentType<BaseComponentType>())
|
||||
{
|
||||
return;
|
||||
}
|
||||
using BaseComponentType = typename InputArrayType::ValueType::ComponentType;
|
||||
|
||||
output = input.NewInstanceBasic();
|
||||
output.Allocate(keys.GetInputRange());
|
||||
|
||||
vtkm::IdComponent numComponents = input.GetNumberOfComponentsFlat();
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
|
||||
{
|
||||
vtkm::worklet::AverageByKey::Run(
|
||||
keys,
|
||||
input.ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::On),
|
||||
output.ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::Off));
|
||||
}
|
||||
|
||||
called = true;
|
||||
vtkm::worklet::AverageByKey::Run(
|
||||
keys, input, output.ExtractArrayFromComponents<BaseComponentType>(vtkm::CopyFlag::Off));
|
||||
}
|
||||
};
|
||||
|
||||
@ -57,23 +41,20 @@ bool vtkm::filter::MapFieldMergeAverage(const vtkm::cont::Field& inputField,
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
vtkm::cont::VariantArrayHandle outputArray;
|
||||
bool calledMap = false;
|
||||
vtkm::ListForEach(DoMapFieldMerge{},
|
||||
vtkm::TypeListScalarAll{},
|
||||
inputField.GetData(),
|
||||
keys,
|
||||
outputArray,
|
||||
calledMap);
|
||||
if (calledMap)
|
||||
vtkm::cont::UnknownArrayHandle outputArray = inputField.GetData().NewInstanceBasic();
|
||||
outputArray.Allocate(keys.GetInputRange());
|
||||
|
||||
try
|
||||
{
|
||||
inputField.GetData().CastAndCallWithExtractedArray(DoMapFieldMerge{}, keys, outputArray);
|
||||
outputField = vtkm::cont::Field(inputField.GetName(), inputField.GetAssociation(), outputArray);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
catch (...)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Faild to map field " << inputField.GetName());
|
||||
return false;
|
||||
}
|
||||
return calledMap;
|
||||
}
|
||||
|
||||
bool vtkm::filter::MapFieldMergeAverage(const vtkm::cont::Field& inputField,
|
||||
|
@ -37,9 +37,12 @@ struct MapPermutationWorklet : vtkm::worklet::WorkletMapField
|
||||
|
||||
using ControlSignature = void(FieldIn permutationIndex, WholeArrayIn input, FieldOut output);
|
||||
|
||||
template <typename InputPortalType>
|
||||
VTKM_EXEC void operator()(vtkm::Id permutationIndex, InputPortalType inputPortal, T& output) const
|
||||
template <typename InputPortalType, typename OutputType>
|
||||
VTKM_EXEC void operator()(vtkm::Id permutationIndex,
|
||||
InputPortalType inputPortal,
|
||||
OutputType& output) const
|
||||
{
|
||||
VTKM_STATIC_ASSERT(vtkm::HasVecTraits<OutputType>::value);
|
||||
if ((permutationIndex >= 0) && (permutationIndex < inputPortal.GetNumberOfValues()))
|
||||
{
|
||||
output = inputPortal.Get(permutationIndex);
|
||||
@ -53,36 +56,21 @@ struct MapPermutationWorklet : vtkm::worklet::WorkletMapField
|
||||
|
||||
struct DoMapFieldPermutation
|
||||
{
|
||||
template <typename BaseComponentType>
|
||||
void operator()(BaseComponentType,
|
||||
const vtkm::cont::UnknownArrayHandle& input,
|
||||
template <typename InputArrayType>
|
||||
void operator()(const InputArrayType& input,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id>& permutation,
|
||||
vtkm::cont::UnknownArrayHandle& output,
|
||||
vtkm::Float64 invalidValue,
|
||||
bool& called) const
|
||||
vtkm::Float64 invalidValue) const
|
||||
{
|
||||
if (!input.IsBaseComponentType<BaseComponentType>())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
output = input.NewInstanceBasic();
|
||||
output.Allocate(permutation.GetNumberOfValues());
|
||||
|
||||
vtkm::IdComponent numComponents = input.GetNumberOfComponentsFlat();
|
||||
using BaseComponentType = typename InputArrayType::ValueType::ComponentType;
|
||||
|
||||
MapPermutationWorklet<BaseComponentType> worklet(
|
||||
vtkm::cont::internal::CastInvalidValue<BaseComponentType>(invalidValue));
|
||||
vtkm::cont::Invoker invoke;
|
||||
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
|
||||
{
|
||||
invoke(worklet,
|
||||
permutation,
|
||||
input.ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::On),
|
||||
output.ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::Off));
|
||||
}
|
||||
|
||||
called = true;
|
||||
vtkm::cont::Invoker{}(
|
||||
worklet,
|
||||
permutation,
|
||||
input,
|
||||
output.ExtractArrayFromComponents<BaseComponentType>(vtkm::CopyFlag::Off));
|
||||
}
|
||||
};
|
||||
|
||||
@ -96,24 +84,20 @@ VTKM_FILTER_COMMON_EXPORT VTKM_CONT bool vtkm::filter::MapFieldPermutation(
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
vtkm::cont::VariantArrayHandle outputArray;
|
||||
bool calledMap = false;
|
||||
vtkm::ListForEach(DoMapFieldPermutation{},
|
||||
vtkm::TypeListScalarAll{},
|
||||
inputField.GetData(),
|
||||
permutation,
|
||||
outputArray,
|
||||
invalidValue,
|
||||
calledMap);
|
||||
if (calledMap)
|
||||
vtkm::cont::UnknownArrayHandle outputArray = inputField.GetData().NewInstanceBasic();
|
||||
outputArray.Allocate(permutation.GetNumberOfValues());
|
||||
try
|
||||
{
|
||||
inputField.GetData().CastAndCallWithExtractedArray(
|
||||
DoMapFieldPermutation{}, permutation, outputArray, invalidValue);
|
||||
outputField = vtkm::cont::Field(inputField.GetName(), inputField.GetAssociation(), outputArray);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
catch (...)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Faild to map field " << inputField.GetName());
|
||||
return false;
|
||||
}
|
||||
return calledMap;
|
||||
}
|
||||
|
||||
VTKM_FILTER_COMMON_EXPORT VTKM_CONT bool vtkm::filter::MapFieldPermutation(
|
||||
|
@ -83,20 +83,16 @@ set(libraries
|
||||
)
|
||||
|
||||
if (VTKm_ENABLE_RENDERING)
|
||||
set(libraries
|
||||
${libraries}
|
||||
vtkm_rendering
|
||||
)
|
||||
list(APPEND libraries vtkm_rendering)
|
||||
|
||||
set(unit_tests
|
||||
${unit_tests}
|
||||
list(APPEND unit_tests
|
||||
RegressionTestContourFilter.cxx
|
||||
RegressionTestPointTransform.cxx
|
||||
RegressionTestSplitSharpEdges.cxx
|
||||
RegressionTestStreamline.cxx
|
||||
RegressionTestSurfaceNormals.cxx
|
||||
)
|
||||
endif (VTKm_ENABLE_RENDERING)
|
||||
endif()
|
||||
|
||||
vtkm_unit_tests(
|
||||
SOURCES ${unit_tests}
|
||||
|
@ -10,10 +10,13 @@
|
||||
|
||||
#include <vtkm/Math.h>
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
#include <vtkm/cont/testing/MakeTestDataSet.h>
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
|
||||
#include <vtkm/filter/CleanGrid.h>
|
||||
#include <vtkm/filter/Contour.h>
|
||||
#include <vtkm/source/Tangle.h>
|
||||
|
||||
#include <vtkm/io/VTKDataSetReader.h>
|
||||
|
||||
#include <vtkm/rendering/CanvasRayTracer.h>
|
||||
@ -53,11 +56,81 @@ void TestContourFilterWedge()
|
||||
auto view = vtkm::rendering::testing::GetViewPtr<M, C, V3>(
|
||||
result, "gyroid", canvas, mapper, scene, colorTable, static_cast<vtkm::FloatDefault>(0.08));
|
||||
|
||||
VTKM_TEST_ASSERT(test_equal_images_matching_name(view, "contour-wedge.png"));
|
||||
VTKM_TEST_ASSERT(test_equal_images(view, "contour-wedge.png"));
|
||||
}
|
||||
|
||||
void TestContourFilterUniform()
|
||||
{
|
||||
std::cout << "Generate Image for Contour filter on a uniform grid" << std::endl;
|
||||
|
||||
vtkm::cont::ColorTable colorTable(
|
||||
{ 0, 1 }, { 0.20f, 0.80f, .20f }, { .20f, .80f, .201f }, vtkm::ColorSpace::RGB);
|
||||
using M = vtkm::rendering::MapperRayTracer;
|
||||
using C = vtkm::rendering::CanvasRayTracer;
|
||||
using V3 = vtkm::rendering::View3D;
|
||||
|
||||
vtkm::cont::testing::MakeTestDataSet maker;
|
||||
vtkm::cont::DataSet inputData = maker.Make3DUniformDataSet0();
|
||||
std::string fieldName = "pointvar";
|
||||
VTKM_TEST_ASSERT(inputData.HasField(fieldName));
|
||||
|
||||
vtkm::filter::Contour contour;
|
||||
contour.SetGenerateNormals(false);
|
||||
contour.SetMergeDuplicatePoints(true);
|
||||
contour.SetIsoValue(0, 100.0);
|
||||
contour.SetActiveField(fieldName);
|
||||
contour.SetFieldsToPass(fieldName);
|
||||
vtkm::cont::DataSet result = contour.Execute(inputData);
|
||||
|
||||
result.PrintSummary(std::cout);
|
||||
|
||||
C canvas(512, 512);
|
||||
M mapper;
|
||||
vtkm::rendering::Scene scene;
|
||||
auto view = vtkm::rendering::testing::GetViewPtr<M, C, V3>(
|
||||
result, "pointvar", canvas, mapper, scene, colorTable);
|
||||
|
||||
//Y axis Flying Edge algorithm has subtle differences at a couple of boundaries
|
||||
VTKM_TEST_ASSERT(test_equal_images(view, "contour-uniform.png"));
|
||||
}
|
||||
|
||||
void TestContourFilterTangle()
|
||||
{
|
||||
std::cout << "Generate Image for Contour filter on a uniform tangle grid" << std::endl;
|
||||
|
||||
vtkm::cont::ColorTable colorTable(
|
||||
{ 0, 1 }, { 0.20f, 0.80f, .20f }, { .20f, .80f, .201f }, vtkm::ColorSpace::RGB);
|
||||
using M = vtkm::rendering::MapperRayTracer;
|
||||
using C = vtkm::rendering::CanvasRayTracer;
|
||||
using V3 = vtkm::rendering::View3D;
|
||||
|
||||
vtkm::Id3 dims(4, 4, 4);
|
||||
vtkm::source::Tangle tangle(dims);
|
||||
vtkm::cont::DataSet dataSet = tangle.Execute();
|
||||
|
||||
vtkm::filter::Contour contour;
|
||||
contour.SetGenerateNormals(true);
|
||||
contour.SetIsoValue(0, 1);
|
||||
contour.SetActiveField("nodevar");
|
||||
contour.SetFieldsToPass("nodevar");
|
||||
auto result = contour.Execute(dataSet);
|
||||
|
||||
result.PrintSummary(std::cout);
|
||||
|
||||
C canvas(512, 512);
|
||||
M mapper;
|
||||
vtkm::rendering::Scene scene;
|
||||
auto view = vtkm::rendering::testing::GetViewPtr<M, C, V3>(
|
||||
result, "nodevar", canvas, mapper, scene, colorTable);
|
||||
|
||||
//Y axis Flying Edge algorithm has subtle differences at a couple of boundaries
|
||||
VTKM_TEST_ASSERT(test_equal_images(view, "contour-tangle.png"));
|
||||
}
|
||||
|
||||
void TestContourFilter()
|
||||
{
|
||||
TestContourFilterUniform();
|
||||
TestContourFilterTangle();
|
||||
TestContourFilterWedge();
|
||||
}
|
||||
} // namespace
|
||||
|
@ -18,7 +18,7 @@ void TestFieldToColors()
|
||||
{
|
||||
//faux input field
|
||||
constexpr vtkm::Id nvals = 8;
|
||||
constexpr int data[nvals] = { -1, 0, 10, 20, 30, 40, 50, 60 };
|
||||
constexpr vtkm::FloatDefault data[nvals] = { -1, 0, 10, 20, 30, 40, 50, 60 };
|
||||
|
||||
//build a color table with clamping off and verify that sampling works
|
||||
vtkm::Range range{ 0.0, 50.0 };
|
||||
|
@ -102,8 +102,8 @@ void TestImageDifference()
|
||||
vtkm::filter::ImageDifference filter;
|
||||
filter.SetPrimaryField("primary");
|
||||
filter.SetSecondaryField("secondary");
|
||||
filter.SetThreshold(0.05f);
|
||||
filter.SetRadius(0);
|
||||
filter.SetPixelDiffThreshold(0.05f);
|
||||
filter.SetPixelShiftRadius(0);
|
||||
vtkm::cont::DataSet result = filter.Execute(dataSet);
|
||||
|
||||
std::vector<vtkm::Vec4f> expectedDiff = {
|
||||
@ -125,9 +125,9 @@ void TestImageDifference()
|
||||
vtkm::filter::ImageDifference filter;
|
||||
filter.SetPrimaryField("primary");
|
||||
filter.SetSecondaryField("secondary");
|
||||
filter.SetThreshold(0.05f);
|
||||
filter.SetRadius(1);
|
||||
filter.SetAveragePixels(true);
|
||||
filter.SetPixelDiffThreshold(0.05f);
|
||||
filter.SetPixelShiftRadius(1);
|
||||
filter.SetAverageRadius(1);
|
||||
vtkm::cont::DataSet result = filter.Execute(dataSet);
|
||||
|
||||
std::vector<vtkm::Vec4f> expectedDiff = {
|
||||
@ -149,8 +149,8 @@ void TestImageDifference()
|
||||
vtkm::filter::ImageDifference filter;
|
||||
filter.SetPrimaryField("primary");
|
||||
filter.SetSecondaryField("secondary");
|
||||
filter.SetThreshold(0.05f);
|
||||
filter.SetRadius(0);
|
||||
filter.SetPixelDiffThreshold(0.05f);
|
||||
filter.SetPixelShiftRadius(0);
|
||||
vtkm::cont::DataSet result = filter.Execute(dataSet);
|
||||
|
||||
std::vector<vtkm::Vec4f> expectedDiff = {
|
||||
@ -166,6 +166,30 @@ void TestImageDifference()
|
||||
expectedDiff, expectedThreshold, result, filter.GetImageDiffWithinThreshold(), false);
|
||||
}
|
||||
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Non Matching Images (Different R pixel)");
|
||||
auto dataSet = FillDataSet(static_cast<vtkm::FloatDefault>(3));
|
||||
vtkm::filter::ImageDifference filter;
|
||||
filter.SetPrimaryField("primary");
|
||||
filter.SetSecondaryField("secondary");
|
||||
filter.SetPixelDiffThreshold(0.05f);
|
||||
filter.SetPixelShiftRadius(0);
|
||||
filter.SetAllowedPixelErrorRatio(1.00f);
|
||||
vtkm::cont::DataSet result = filter.Execute(dataSet);
|
||||
|
||||
std::vector<vtkm::Vec4f> expectedDiff = {
|
||||
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
|
||||
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
|
||||
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
|
||||
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
|
||||
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }
|
||||
};
|
||||
std::vector<vtkm::FloatDefault> expectedThreshold = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
|
||||
CheckResult(
|
||||
expectedDiff, expectedThreshold, result, filter.GetImageDiffWithinThreshold(), true);
|
||||
}
|
||||
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
"Non Matching Images (Different R pixel), Large Threshold");
|
||||
@ -173,8 +197,8 @@ void TestImageDifference()
|
||||
vtkm::filter::ImageDifference filter;
|
||||
filter.SetPrimaryField("primary");
|
||||
filter.SetSecondaryField("secondary");
|
||||
filter.SetThreshold(3.0f);
|
||||
filter.SetRadius(0);
|
||||
filter.SetPixelDiffThreshold(3.0f);
|
||||
filter.SetPixelShiftRadius(0);
|
||||
vtkm::cont::DataSet result = filter.Execute(dataSet);
|
||||
|
||||
std::vector<vtkm::Vec4f> expectedDiff = {
|
||||
|
@ -70,7 +70,7 @@ vtkm::cont::PartitionedDataSet PartitionedDataSetBuilder(std::size_t partitionNu
|
||||
}
|
||||
return partitions;
|
||||
}
|
||||
template <typename D>
|
||||
template <typename T, typename D>
|
||||
void Result_Verify(const vtkm::cont::PartitionedDataSet& result,
|
||||
D& filter,
|
||||
const vtkm::cont::PartitionedDataSet& partitions,
|
||||
@ -88,9 +88,9 @@ void Result_Verify(const vtkm::cont::PartitionedDataSet& result,
|
||||
partitionResult.GetField(outputFieldName).GetNumberOfValues(),
|
||||
"result vectors' size incorrect");
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> partitionArray;
|
||||
vtkm::cont::ArrayHandle<T> partitionArray;
|
||||
result.GetPartition(j).GetField(outputFieldName).GetData().CopyTo(partitionArray);
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> sDataSetArray;
|
||||
vtkm::cont::ArrayHandle<T> sDataSetArray;
|
||||
partitionResult.GetField(outputFieldName).GetData().CopyTo(sDataSetArray);
|
||||
|
||||
const vtkm::Id numValues = result.GetPartition(j).GetField(outputFieldName).GetNumberOfValues();
|
||||
@ -109,12 +109,12 @@ void TestPartitionedDataSetFilters()
|
||||
vtkm::cont::PartitionedDataSet result;
|
||||
vtkm::cont::PartitionedDataSet partitions;
|
||||
|
||||
partitions = PartitionedDataSetBuilder<vtkm::Id>(partitionNum, "pointvar");
|
||||
partitions = PartitionedDataSetBuilder<vtkm::FloatDefault>(partitionNum, "pointvar");
|
||||
vtkm::filter::CellAverage cellAverage;
|
||||
cellAverage.SetOutputFieldName("average");
|
||||
cellAverage.SetActiveField("pointvar");
|
||||
result = cellAverage.Execute(partitions);
|
||||
Result_Verify(result, cellAverage, partitions, std::string("pointvar"));
|
||||
Result_Verify<vtkm::FloatDefault>(result, cellAverage, partitions, std::string("pointvar"));
|
||||
}
|
||||
|
||||
int UnitTestPartitionedDataSetFilters(int argc, char* argv[])
|
||||
|
@ -19,6 +19,39 @@ namespace vtkm
|
||||
namespace internal
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// TODO: VecTraits should just always be supported. See #589.
|
||||
|
||||
template <typename Vec, typename = typename std::enable_if<vtkm::HasVecTraits<Vec>::value>::type>
|
||||
VTKM_EXEC_CONT inline vtkm::IdComponent SafeGetNumberOfComponents(const Vec& vec)
|
||||
{
|
||||
return vtkm::VecTraits<Vec>::GetNumberOfComponents(vec);
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT inline vtkm::IdComponent SafeGetNumberOfComponents(...)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename Vec, typename = typename std::enable_if<vtkm::HasVecTraits<Vec>::value>::type>
|
||||
VTKM_EXEC_CONT inline typename vtkm::VecTraits<Vec>::ComponentType SafeGetComponent(
|
||||
const Vec& vec,
|
||||
vtkm::IdComponent index)
|
||||
{
|
||||
return vtkm::VecTraits<Vec>::GetComponent(vec, index);
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<!vtkm::HasVecTraits<T>::value>::type>
|
||||
VTKM_EXEC_CONT inline T SafeGetComponent(const T& value, vtkm::IdComponent index)
|
||||
{
|
||||
VTKM_ASSERT(index == 0);
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \brief A value class for returning setable values of an ArrayPortal
|
||||
///
|
||||
/// \c ArrayPortal classes have a pair of \c Get and \c Set methods that
|
||||
@ -312,6 +345,19 @@ struct ArrayPortalValueReference
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// Support Vec operations so that the reference can be treated as such Vec objects. Note
|
||||
// that although the [] operator is supported, you can only read components this way. You
|
||||
// cannot write components one at a time.
|
||||
VTKM_EXEC_CONT vtkm::IdComponent GetNumberOfComponents() const
|
||||
{
|
||||
return detail::SafeGetNumberOfComponents(static_cast<ValueType>(*this));
|
||||
}
|
||||
VTKM_EXEC_CONT auto operator[](vtkm::IdComponent index) const
|
||||
-> decltype(detail::SafeGetComponent(std::declval<ValueType>(), index))
|
||||
{
|
||||
return detail::SafeGetComponent(static_cast<ValueType>(*this), index);
|
||||
}
|
||||
|
||||
private:
|
||||
const ArrayPortalType& Portal;
|
||||
vtkm::Id Index;
|
||||
|
@ -86,7 +86,8 @@ struct OutputArrayDataFunctor
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T, const vtkm::cont::UnknownArrayHandle& array, std::ostream& out) const
|
||||
{
|
||||
auto portal = array.ReadPortalForBaseComponentType<T>();
|
||||
auto componentArray = array.ExtractArrayFromComponents<T>();
|
||||
auto portal = componentArray.ReadPortal();
|
||||
|
||||
vtkm::Id numValues = portal.GetNumberOfValues();
|
||||
for (vtkm::Id valueIndex = 0; valueIndex < numValues; ++valueIndex)
|
||||
|
@ -19,16 +19,16 @@ set(unit_tests
|
||||
set(unit_test_libraries vtkm_lodepng vtkm_io)
|
||||
|
||||
if(VTKm_ENABLE_RENDERING)
|
||||
set(unit_tests ${unit_tests}
|
||||
list(APPEND unit_tests
|
||||
UnitTestImageWriter.cxx
|
||||
)
|
||||
)
|
||||
|
||||
if (VTKm_ENABLE_HDF5_IO)
|
||||
set(unit_tests ${unit_tests}
|
||||
list(APPEND unit_tests
|
||||
UnitTestHDF5Image.cxx)
|
||||
endif()
|
||||
|
||||
set(unit_test_libraries ${unit_test_libraries} vtkm_rendering)
|
||||
list(APPEND unit_test_libraries vtkm_rendering)
|
||||
endif()
|
||||
|
||||
vtkm_unit_tests(SOURCES ${unit_tests} ALL_BACKENDS LIBRARIES ${unit_test_libraries})
|
||||
|
@ -44,6 +44,13 @@ struct CheckSameCoordinateSystem
|
||||
CheckSameField{}(originalArray, fileCoords);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator()(const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagSOA>& originalArray,
|
||||
const vtkm::cont::CoordinateSystem& fileCoords) const
|
||||
{
|
||||
CheckSameField{}(originalArray, fileCoords);
|
||||
}
|
||||
|
||||
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
|
||||
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
||||
template <typename T>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user