vtk-m/vtkm/cont/internal/StorageDeprecated.h
Kenneth Moreland 05f144eb19 Allow ArrayHandle to have a runtime selectable number of buffers
Previously, the number of buffers held by an `ArrayHandle` had to be
determined statically at compile time by the storage. Most of the time
this is fine. However, there are some exceptions where the number of
buffers need to be selected at runtime. For example, the
`ArrayHandleRecombineVec` does not specify the number of components it
uses, and it needed a hack where it stored buffers in the metadata of
another buffer, which is bad.

This change allows the number of buffers to vary at runtime (at least at
construction). The buffers were already managed in a `std::vector`. It
now no longer forces the vector to be a specific size.
`GetNumberOfBuffers` was removed from the `Storage`. Instead, if the
number of buffers was not specified at construction, an allocation of
size 0 is done to create default buffers.

The biggest change is to the interface of the storage object methods,
which now take `std::vector` instead of pointers to `Buffer` objects.
This adds a little hastle in having to copy subsets of this `vector`
when a storage object has multiple sub-arrays. But it does simplify some
of the templating.
2022-07-11 07:48:25 -06:00

227 lines
7.7 KiB
C++

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_internal_StorageDeprecated_h
#define vtk_m_cont_internal_StorageDeprecated_h
#include <vtkm/cont/ErrorBadDevice.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/Storage.h>
#include <vtkm/cont/Token.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/cont/internal/Buffer.h>
#include <vtkm/internal/ArrayPortalHelpers.h>
namespace vtkm
{
namespace cont
{
namespace internal
{
template <typename T, typename S>
class ArrayHandleDeprecated;
namespace detail
{
struct TryPrepareInput
{
template <typename Device, typename ArrayType>
VTKM_CONT bool operator()(Device device,
ArrayType&& array,
vtkm::cont::Token& token,
typename ArrayType::ReadPortalType& portal,
bool& created) const
{
if (!created)
{
portal = array.PrepareForInput(device, token);
created = true;
}
return true;
}
};
struct TryPrepareInPlace
{
template <typename Device, typename ArrayType>
VTKM_CONT bool operator()(Device device,
ArrayType&& array,
vtkm::cont::Token& token,
typename ArrayType::WritePortalType& portal,
bool& created) const
{
if (!created)
{
portal = array.PrepareForInPlace(device, token);
created = true;
}
return true;
}
};
template <typename StorageType>
struct StorageTemplateParams;
template <typename T, typename S>
struct StorageTemplateParams<vtkm::cont::internal::Storage<T, S>>
{
using ValueType = T;
using StorageTag = S;
};
} // namespace detail
/// \brief `Storage` handler for `ArrayHandle` types still using old `ArrayHandle` style.
///
/// A recent change to `ArrayHandle` moved from using the `ArrayTransfer` method for
/// moving data from control to execution environments to using `Buffer` objects. One
/// feature of the `Buffer` objects is that if you have a new style `ArrayHandle` that
/// deprecates other `ArrayHandle`s, they both have to use `Buffer`.
///
/// All old-style `ArrayHandle`s that still use `ArrayTransfer` should have a
/// `VTKM_STORAGE_OLD_STYLE;` declaration at the bottom of the `Storage` class.
///
template <typename StorageType, typename ReadPortalType, typename WritePortalType>
class StorageDeprecated
{
using T = typename detail::StorageTemplateParams<StorageType>::ValueType;
using StorageTag = typename detail::StorageTemplateParams<StorageType>::StorageTag;
using ArrayType = vtkm::cont::internal::ArrayHandleDeprecated<T, StorageTag>;
VTKM_CONT static ArrayType GetArray(const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return buffers[0].GetMetaData<ArrayType>();
}
public:
VTKM_CONT static vtkm::Id GetNumberOfValues(
const std::vector<vtkm::cont::internal::Buffer>& buffers)
{
return GetArray(buffers).GetNumberOfValues();
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::CopyFlag preserve,
vtkm::cont::Token& token)
{
switch (preserve)
{
case vtkm::CopyFlag::Off:
GetArray(buffers).Allocate(numValues, token);
break;
case vtkm::CopyFlag::On:
GetArray(buffers).Shrink(numValues, token);
break;
}
}
VTKM_CONT static ReadPortalType CreateReadPortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
if (device == vtkm::cont::DeviceAdapterTagUndefined{})
{
return GetArray(buffers).ReadPortal();
}
else
{
ReadPortalType portal;
bool created = false;
vtkm::cont::TryExecuteOnDevice(
device, detail::TryPrepareInput{}, GetArray(buffers), token, portal, created);
if (!created)
{
throw vtkm::cont::ErrorBadDevice("Failed to create input portal for device " +
device.GetName());
}
return portal;
}
}
private:
VTKM_CONT static WritePortalType CreateWritePortalImpl(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token,
std::true_type)
{
if (device == vtkm::cont::DeviceAdapterTagUndefined{})
{
return GetArray(buffers).WritePortal();
}
else
{
WritePortalType portal;
bool created = false;
vtkm::cont::TryExecuteOnDevice(
device, detail::TryPrepareInPlace{}, GetArray(buffers), token, portal, created);
if (!created)
{
throw vtkm::cont::ErrorBadDevice("Failed to create in place portal for device " +
device.GetName());
}
return portal;
}
}
VTKM_CONT static WritePortalType CreateWritePortalImpl(
const std::vector<vtkm::cont::internal::Buffer>&,
vtkm::cont::DeviceAdapterId,
vtkm::cont::Token&,
std::false_type)
{
throw vtkm::cont::ErrorBadType("Attempted to get a writable portal to a read-only array.");
}
using SupportsWrite = vtkm::internal::PortalSupportsSets<WritePortalType>;
public:
VTKM_CONT static WritePortalType CreateWritePortal(
const std::vector<vtkm::cont::internal::Buffer>& buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
return CreateWritePortalImpl(buffers, device, token, SupportsWrite{});
}
};
#define VTKM_STORAGE_OLD_STYLE \
public: \
using HasOldBridge = std::true_type; \
using ReadPortalType = PortalConstType; \
using WritePortalType = PortalType; \
\
private: \
using StorageDeprecated = \
vtkm::cont::internal::StorageDeprecated<Storage, ReadPortalType, WritePortalType>; \
\
public: \
VTKM_CONT static vtkm::Id GetNumberOfValues( \
const std::vector<vtkm::cont::internal::Buffer>& buffers) \
{ \
return StorageDeprecated::GetNumberOfValues(buffers); \
} \
static constexpr auto& ResizeBuffers = StorageDeprecated::ResizeBuffers; \
static constexpr auto& CreateReadPortal = StorageDeprecated::CreateReadPortal; \
static constexpr auto& CreateWritePortal = StorageDeprecated::CreateWritePortal
}
}
} // namespace vtkm::cont::internal
#endif //vtk_m_cont_internal_StorageDeprecated_h