mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 18:08:59 +00:00
287 lines
11 KiB
C++
287 lines
11 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_DeviceAdapterMemoryManager_h
|
|
#define vtk_m_cont_internal_DeviceAdapterMemoryManager_h
|
|
|
|
#include <vtkm/cont/vtkm_cont_export.h>
|
|
|
|
#include <vtkm/Flags.h>
|
|
#include <vtkm/Types.h>
|
|
|
|
#include <vtkm/cont/DeviceAdapterTag.h>
|
|
|
|
#include <cstring>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
namespace vtkm
|
|
{
|
|
|
|
using BufferSizeType = vtkm::Int64;
|
|
|
|
namespace cont
|
|
{
|
|
namespace internal
|
|
{
|
|
|
|
struct TransferredBuffer;
|
|
|
|
namespace detail
|
|
{
|
|
|
|
struct BufferInfoInternals;
|
|
|
|
} // namespace detail
|
|
|
|
class VTKM_CONT_EXPORT BufferInfo
|
|
{
|
|
public:
|
|
/// Returns a pointer to the memory that is allocated. This pointer may only be referenced on
|
|
/// the associated device.
|
|
///
|
|
VTKM_CONT void* GetPointer() const;
|
|
|
|
/// Returns the size of the buffer in bytes.
|
|
///
|
|
VTKM_CONT vtkm::BufferSizeType GetSize() const;
|
|
|
|
/// \brief Returns the device on which this buffer is allocated.
|
|
///
|
|
/// If the buffer is not on a device (i.e. it is on the host), then DeviceAdapterIdUndefined
|
|
/// is returned.
|
|
///
|
|
VTKM_CONT vtkm::cont::DeviceAdapterId GetDevice() const;
|
|
|
|
VTKM_CONT BufferInfo();
|
|
VTKM_CONT ~BufferInfo();
|
|
|
|
VTKM_CONT BufferInfo(const BufferInfo& src);
|
|
VTKM_CONT BufferInfo(BufferInfo&& src);
|
|
|
|
VTKM_CONT BufferInfo& operator=(const BufferInfo& src);
|
|
VTKM_CONT BufferInfo& operator=(BufferInfo&& src);
|
|
|
|
/// Shallow copy buffer from one host/device to another host/device. Make sure that these
|
|
/// two devices share the same memory space. (This is not checked and will cause badness
|
|
/// if not correct.)
|
|
///
|
|
VTKM_CONT BufferInfo(const BufferInfo& src, vtkm::cont::DeviceAdapterId device);
|
|
VTKM_CONT BufferInfo(BufferInfo&& src, vtkm::cont::DeviceAdapterId device);
|
|
|
|
/// A function callback for deleting the memory.
|
|
///
|
|
using Deleter = void(void* container);
|
|
|
|
/// A function callback for reallocating the memory.
|
|
///
|
|
using Reallocater = void(void*& memory,
|
|
void*& container,
|
|
vtkm::BufferSizeType oldSize,
|
|
vtkm::BufferSizeType newSize);
|
|
|
|
/// Creates a BufferInfo with the given memory, some (unknown) container holding that memory, a
|
|
/// deletion function, and a reallocation function. The deleter will be called with the pointer
|
|
/// to the container when the buffer is released.
|
|
///
|
|
VTKM_CONT BufferInfo(vtkm::cont::DeviceAdapterId device,
|
|
void* memory,
|
|
void* container,
|
|
vtkm::BufferSizeType size,
|
|
Deleter deleter,
|
|
Reallocater reallocater);
|
|
|
|
/// Reallocates the buffer to a new size.
|
|
///
|
|
VTKM_CONT void Reallocate(vtkm::BufferSizeType newSize);
|
|
|
|
/// Transfers ownership of the underlying allocation and Deleter and Reallocater to the caller.
|
|
/// After ownership has been transferred this buffer will be equivalant to one that was passed
|
|
/// to VTK-m as `view` only.
|
|
///
|
|
/// This means that the Deleter will do nothing, and the Reallocater will throw an `ErrorBadAllocation`.
|
|
///
|
|
VTKM_CONT TransferredBuffer TransferOwnership();
|
|
|
|
private:
|
|
detail::BufferInfoInternals* Internals;
|
|
vtkm::cont::DeviceAdapterId Device;
|
|
};
|
|
|
|
|
|
/// Represents the buffer being transferred to external ownership
|
|
///
|
|
/// The Memory pointer represents the actual data allocation to
|
|
/// be used for access and execution
|
|
///
|
|
/// The container represents what needs to be deleted. This might
|
|
/// not be equivalent to \c Memory when we have transferred things
|
|
/// such as std::vector
|
|
///
|
|
struct TransferredBuffer
|
|
{
|
|
void* Memory;
|
|
void* Container;
|
|
BufferInfo::Deleter* Delete;
|
|
BufferInfo::Reallocater* Reallocate;
|
|
vtkm::BufferSizeType Size;
|
|
};
|
|
|
|
/// Allocates a `BufferInfo` object for the host.
|
|
///
|
|
VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::internal::BufferInfo AllocateOnHost(
|
|
vtkm::BufferSizeType size);
|
|
|
|
/// \brief The base class for device adapter memory managers.
|
|
///
|
|
/// Every device adapter is expected to define a specialization of `DeviceAdapterMemoryManager`,
|
|
/// and they are all expected to subclass this base class.
|
|
///
|
|
class VTKM_CONT_EXPORT DeviceAdapterMemoryManagerBase
|
|
{
|
|
public:
|
|
VTKM_CONT virtual ~DeviceAdapterMemoryManagerBase();
|
|
|
|
/// Allocates a buffer of the specified size in bytes and returns a BufferInfo object
|
|
/// containing information about it.
|
|
VTKM_CONT virtual vtkm::cont::internal::BufferInfo Allocate(vtkm::BufferSizeType size) const = 0;
|
|
|
|
/// Reallocates the provided buffer to a new size. The passed in `BufferInfo` should be
|
|
/// modified to reflect the changes.
|
|
VTKM_CONT void Reallocate(vtkm::cont::internal::BufferInfo& buffer,
|
|
vtkm::BufferSizeType newSize) const;
|
|
|
|
/// Manages the provided array. Returns a `BufferInfo` object that contains the data.
|
|
VTKM_CONT BufferInfo ManageArray(void* memory,
|
|
void* container,
|
|
vtkm::BufferSizeType size,
|
|
vtkm::cont::internal::BufferInfo::Deleter deleter,
|
|
vtkm::cont::internal::BufferInfo::Reallocater reallocater) const;
|
|
|
|
/// Returns the device that this manager is associated with.
|
|
VTKM_CONT virtual vtkm::cont::DeviceAdapterId GetDevice() const = 0;
|
|
|
|
/// Copies data from the provided host buffer provided onto the device and returns a buffer info
|
|
/// object holding the pointer for the device.
|
|
VTKM_CONT virtual vtkm::cont::internal::BufferInfo CopyHostToDevice(
|
|
const vtkm::cont::internal::BufferInfo& src) const = 0;
|
|
|
|
/// Copies data from the provided host buffer into the provided pre-allocated device buffer. The
|
|
/// `BufferInfo` object for the device was created by a previous call to this object.
|
|
VTKM_CONT virtual void CopyHostToDevice(const vtkm::cont::internal::BufferInfo& src,
|
|
const vtkm::cont::internal::BufferInfo& dest) const = 0;
|
|
|
|
/// Copies data from the device buffer provided to the host. The passed in `BufferInfo` object
|
|
/// was created by a previous call to this object.
|
|
VTKM_CONT virtual vtkm::cont::internal::BufferInfo CopyDeviceToHost(
|
|
const vtkm::cont::internal::BufferInfo& src) const = 0;
|
|
|
|
/// Copies data from the device buffer provided into the provided pre-allocated host buffer. The
|
|
/// `BufferInfo` object for the device was created by a previous call to this object.
|
|
VTKM_CONT virtual void CopyDeviceToHost(const vtkm::cont::internal::BufferInfo& src,
|
|
const vtkm::cont::internal::BufferInfo& dest) const = 0;
|
|
|
|
/// Deep copies data from one device buffer to another device buffer. The passed in `BufferInfo`
|
|
/// object was created by a previous call to this object.
|
|
VTKM_CONT virtual vtkm::cont::internal::BufferInfo CopyDeviceToDevice(
|
|
const vtkm::cont::internal::BufferInfo& src) const = 0;
|
|
|
|
/// Deep copies data from one device buffer to another device buffer. The passed in `BufferInfo`
|
|
/// objects were created by a previous call to this object.
|
|
VTKM_CONT virtual void CopyDeviceToDevice(const vtkm::cont::internal::BufferInfo& src,
|
|
const vtkm::cont::internal::BufferInfo& dest) const = 0;
|
|
};
|
|
|
|
/// \brief The device adapter memory manager.
|
|
///
|
|
/// Every device adapter is expected to define a specialization of `DeviceAdapterMemoryManager`.
|
|
/// This class must be a (perhaps indirect) subclass of `DeviceAdapterMemoryManagerBase`. All
|
|
/// abstract methods must be implemented.
|
|
///
|
|
template <typename DeviceAdapterTag>
|
|
class DeviceAdapterMemoryManager;
|
|
|
|
VTKM_CONT_EXPORT VTKM_CONT void InvalidRealloc(void*&,
|
|
void*&,
|
|
vtkm::BufferSizeType,
|
|
vtkm::BufferSizeType);
|
|
|
|
// Deletes a container object by casting it to a pointer of a given type (the template argument)
|
|
// and then using delete[] on the object.
|
|
template <typename T>
|
|
VTKM_CONT inline void SimpleArrayDeleter(void* container_)
|
|
{
|
|
T* container = reinterpret_cast<T*>(container_);
|
|
delete[] container;
|
|
}
|
|
|
|
// Reallocates a standard C array. Note that the allocation method is different than the default
|
|
// host allocation of vtkm::cont::internal::BufferInfo and may be less efficient.
|
|
template <typename T>
|
|
VTKM_CONT inline void SimpleArrayReallocater(void*& memory,
|
|
void*& container,
|
|
vtkm::BufferSizeType oldSize,
|
|
vtkm::BufferSizeType newSize)
|
|
{
|
|
VTKM_ASSERT(memory == container);
|
|
VTKM_ASSERT(static_cast<std::size_t>(newSize) % sizeof(T) == 0);
|
|
|
|
// If the new size is not much smaller than the old size, just reuse the buffer (and waste a
|
|
// little memory).
|
|
if ((newSize > ((3 * oldSize) / 4)) && (newSize <= oldSize))
|
|
{
|
|
return;
|
|
}
|
|
|
|
void* newBuffer = new T[static_cast<std::size_t>(newSize) / sizeof(T)];
|
|
std::memcpy(newBuffer, memory, static_cast<std::size_t>(newSize < oldSize ? newSize : oldSize));
|
|
|
|
if (memory != nullptr)
|
|
{
|
|
SimpleArrayDeleter<T>(memory);
|
|
}
|
|
|
|
memory = container = newBuffer;
|
|
}
|
|
|
|
// Deletes a container object by casting it to a pointer of a given type (the template argument)
|
|
// and then using delete on the object.
|
|
template <typename T>
|
|
VTKM_CONT inline void CastDeleter(void* container_)
|
|
{
|
|
T* container = reinterpret_cast<T*>(container_);
|
|
delete container;
|
|
}
|
|
|
|
template <typename T, typename Allocator>
|
|
VTKM_CONT inline void StdVectorDeleter(void* container)
|
|
{
|
|
CastDeleter<std::vector<T, Allocator>>(container);
|
|
}
|
|
|
|
template <typename T, typename Allocator>
|
|
VTKM_CONT inline void StdVectorReallocater(void*& memory,
|
|
void*& container,
|
|
vtkm::BufferSizeType oldSize,
|
|
vtkm::BufferSizeType newSize)
|
|
{
|
|
using vector_type = std::vector<T, Allocator>;
|
|
vector_type* vector = reinterpret_cast<vector_type*>(container);
|
|
VTKM_ASSERT(vector->empty() || (memory == vector->data()));
|
|
VTKM_ASSERT(oldSize == static_cast<vtkm::BufferSizeType>(vector->size()));
|
|
|
|
vector->resize(static_cast<std::size_t>(newSize));
|
|
memory = vector->data();
|
|
}
|
|
}
|
|
}
|
|
} // namespace vtkm::cont::internal
|
|
|
|
#endif //vtk_m_cont_internal_DeviceAdapterMemoryManager_h
|