2015-08-26 16:30:15 +00:00
|
|
|
//============================================================================
|
|
|
|
// Copyright (c) Kitware, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
// See LICENSE.txt for details.
|
2019-04-15 23:24:21 +00:00
|
|
|
//
|
2015-08-26 16:30:15 +00:00
|
|
|
// 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.
|
|
|
|
//============================================================================
|
2016-04-13 19:52:15 +00:00
|
|
|
#ifndef vtk_m_interop_internal_TransferToOpenGL_h
|
|
|
|
#define vtk_m_interop_internal_TransferToOpenGL_h
|
2015-08-26 16:30:15 +00:00
|
|
|
|
|
|
|
#include <vtkm/cont/ArrayHandle.h>
|
2020-07-06 15:14:32 +00:00
|
|
|
#include <vtkm/cont/Storage.h>
|
2015-08-26 16:30:15 +00:00
|
|
|
|
2017-08-15 19:56:44 +00:00
|
|
|
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
|
|
|
|
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
|
|
|
|
#include <vtkm/cont/tbb/DeviceAdapterTBB.h>
|
|
|
|
|
2016-04-13 19:52:15 +00:00
|
|
|
#include <vtkm/interop/BufferState.h>
|
2017-05-18 14:51:24 +00:00
|
|
|
#include <vtkm/interop/internal/OpenGLHeaders.h>
|
2015-11-03 15:22:32 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace interop
|
|
|
|
{
|
|
|
|
namespace internal
|
|
|
|
{
|
2015-08-26 16:30:15 +00:00
|
|
|
|
2017-08-15 19:56:44 +00:00
|
|
|
/// \brief smp backend and opengl interop resource management
|
|
|
|
///
|
|
|
|
/// \c TransferResource manages any extra memory allocation that is required
|
|
|
|
/// When binding an implicit array handle to opengl
|
|
|
|
///
|
|
|
|
///
|
|
|
|
class SMPTransferResource : public vtkm::interop::internal::TransferResource
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
template <typename T>
|
|
|
|
SMPTransferResource(T, vtkm::Id numberOfValues)
|
|
|
|
: vtkm::interop::internal::TransferResource()
|
|
|
|
, Size(0)
|
|
|
|
, TempStorage()
|
|
|
|
{
|
|
|
|
this->resize<T>(numberOfValues);
|
|
|
|
}
|
|
|
|
|
|
|
|
~SMPTransferResource() {}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void resize(vtkm::Id numberOfValues)
|
|
|
|
{
|
|
|
|
if (this->Size != numberOfValues)
|
|
|
|
{
|
|
|
|
this->Size = numberOfValues;
|
2019-09-10 14:49:48 +00:00
|
|
|
T* storage = new T[static_cast<std::size_t>(this->Size)];
|
2017-08-15 19:56:44 +00:00
|
|
|
this->TempStorage.reset(reinterpret_cast<vtkm::UInt8*>(storage));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> handle(vtkm::Id size) const
|
|
|
|
{
|
|
|
|
VTKM_ASSERT(this->Size > 0);
|
|
|
|
VTKM_ASSERT(this->Size >= size);
|
|
|
|
|
|
|
|
T* storage = reinterpret_cast<T*>(this->TempStorage.get());
|
|
|
|
//construct a handle that is a view onto the memory
|
2020-08-03 16:15:16 +00:00
|
|
|
return vtkm::cont::make_ArrayHandle(storage, size, vtkm::CopyFlag::Off);
|
2017-08-15 19:56:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T* as() const
|
|
|
|
{
|
|
|
|
VTKM_ASSERT(this->Size > 0);
|
|
|
|
T* storage = reinterpret_cast<T*>(this->TempStorage.get());
|
|
|
|
return storage;
|
|
|
|
}
|
|
|
|
|
|
|
|
vtkm::Id Size;
|
|
|
|
std::unique_ptr<vtkm::UInt8[]> TempStorage;
|
|
|
|
};
|
|
|
|
|
2015-08-26 16:30:15 +00:00
|
|
|
namespace detail
|
|
|
|
{
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <class ValueType, class StorageTag, class DeviceAdapterTag>
|
2018-12-27 16:44:19 +00:00
|
|
|
VTKM_CONT void CopyFromHandle(const vtkm::cont::ArrayHandle<ValueType, StorageTag>& handle,
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::interop::BufferState& state,
|
|
|
|
DeviceAdapterTag)
|
2015-08-26 16:30:15 +00:00
|
|
|
{
|
|
|
|
//Generic implementation that will work no matter what. We copy the data
|
2017-08-15 19:56:44 +00:00
|
|
|
//in the given handle to storage held by the buffer state.
|
2015-08-26 16:30:15 +00:00
|
|
|
const vtkm::Id numberOfValues = handle.GetNumberOfValues();
|
2015-09-29 14:24:34 +00:00
|
|
|
const GLsizeiptr size =
|
2017-05-18 14:29:41 +00:00
|
|
|
static_cast<GLsizeiptr>(sizeof(ValueType)) * static_cast<GLsizeiptr>(numberOfValues);
|
2015-08-26 16:30:15 +00:00
|
|
|
|
2017-08-15 19:56:44 +00:00
|
|
|
//grab the temporary storage from the buffer resource
|
|
|
|
vtkm::interop::internal::SMPTransferResource* resource =
|
|
|
|
dynamic_cast<vtkm::interop::internal::SMPTransferResource*>(state.GetResource());
|
2015-08-26 16:30:15 +00:00
|
|
|
|
2015-11-03 15:22:32 +00:00
|
|
|
//Determine if we need to reallocate the buffer
|
|
|
|
state.SetSize(size);
|
|
|
|
const bool resize = state.ShouldRealloc(size);
|
2017-08-15 19:56:44 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
if (resize)
|
2015-11-03 15:22:32 +00:00
|
|
|
{
|
|
|
|
//Allocate the memory and set it as GL_DYNAMIC_DRAW draw
|
|
|
|
glBufferData(state.GetType(), size, 0, GL_DYNAMIC_DRAW);
|
|
|
|
state.SetCapacity(size);
|
2017-08-15 19:56:44 +00:00
|
|
|
|
|
|
|
//If we have an existing resource reallocate it to fit our new size
|
|
|
|
if (resource)
|
|
|
|
{
|
|
|
|
resource->resize<ValueType>(numberOfValues);
|
|
|
|
}
|
2015-11-03 15:22:32 +00:00
|
|
|
}
|
|
|
|
|
2017-08-15 19:56:44 +00:00
|
|
|
//if we don't have a valid resource make a new one. We do this after the
|
|
|
|
//resize check so we don't double allocate when resource == nullptr and
|
|
|
|
//resize == true
|
|
|
|
if (!resource)
|
|
|
|
{
|
|
|
|
resource = new vtkm::interop::internal::SMPTransferResource(ValueType(), numberOfValues);
|
|
|
|
state.SetResource(resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapterTag>;
|
|
|
|
auto resourceHandle = resource->handle<ValueType>(numberOfValues);
|
|
|
|
Algorithm::Copy(handle, resourceHandle);
|
2015-08-26 16:30:15 +00:00
|
|
|
|
2017-08-15 19:56:44 +00:00
|
|
|
//copy into opengl buffer
|
|
|
|
glBufferSubData(state.GetType(), 0, size, resource->as<ValueType>());
|
2015-08-26 16:30:15 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <class ValueType, class DeviceAdapterTag>
|
|
|
|
VTKM_CONT void CopyFromHandle(
|
2018-12-27 16:44:19 +00:00
|
|
|
const vtkm::cont::ArrayHandle<ValueType, vtkm::cont::StorageTagBasic>& handle,
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::interop::BufferState& state,
|
|
|
|
DeviceAdapterTag)
|
2015-08-26 16:30:15 +00:00
|
|
|
{
|
|
|
|
//Specialization given that we are use an C allocated array storage tag
|
|
|
|
//that allows us to directly hook into the data. We pull the data
|
2016-01-25 15:12:18 +00:00
|
|
|
//back to the control environment using PerpareForInput and give an iterator
|
2015-08-26 16:30:15 +00:00
|
|
|
//from the portal to OpenGL to upload to the rendering system
|
|
|
|
//This also works because we know that this class isn't used for cuda interop,
|
|
|
|
//instead we are specialized
|
2017-05-18 14:29:41 +00:00
|
|
|
const GLsizeiptr size = static_cast<GLsizeiptr>(sizeof(ValueType)) *
|
|
|
|
static_cast<GLsizeiptr>(handle.GetNumberOfValues());
|
2015-08-26 16:30:15 +00:00
|
|
|
|
2015-11-03 15:22:32 +00:00
|
|
|
//Determine if we need to reallocate the buffer
|
|
|
|
state.SetSize(size);
|
|
|
|
const bool resize = state.ShouldRealloc(size);
|
2017-05-18 14:29:41 +00:00
|
|
|
if (resize)
|
2015-11-03 15:22:32 +00:00
|
|
|
{
|
|
|
|
//Allocate the memory and set it as GL_DYNAMIC_DRAW draw
|
|
|
|
glBufferData(state.GetType(), size, 0, GL_DYNAMIC_DRAW);
|
|
|
|
|
|
|
|
state.SetCapacity(size);
|
|
|
|
}
|
2015-08-26 16:30:15 +00:00
|
|
|
|
|
|
|
//Allocate the memory and set it as static draw and copy into opengl
|
2020-06-05 14:01:02 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
auto portal = handle.PrepareForInput(DeviceAdapterTag{}, token);
|
|
|
|
const ValueType* memory = &(*vtkm::cont::ArrayPortalToIteratorBegin(portal));
|
2017-05-18 14:29:41 +00:00
|
|
|
glBufferSubData(state.GetType(), 0, size, memory);
|
2015-08-26 16:30:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} //namespace detail
|
|
|
|
|
|
|
|
/// \brief Manages transferring an ArrayHandle to opengl .
|
|
|
|
///
|
|
|
|
/// \c TransferToOpenGL manages to transfer the contents of an ArrayHandle
|
|
|
|
/// to OpenGL as efficiently as possible.
|
|
|
|
///
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename ValueType, class DeviceAdapterTag>
|
2015-08-26 16:30:15 +00:00
|
|
|
class TransferToOpenGL
|
|
|
|
{
|
|
|
|
public:
|
2017-05-18 14:29:41 +00:00
|
|
|
VTKM_CONT explicit TransferToOpenGL(BufferState& state)
|
|
|
|
: State(state)
|
2015-11-03 15:22:32 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
if (!this->State.HasType())
|
2015-11-03 15:22:32 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
this->State.DeduceAndSetType(ValueType());
|
2015-11-03 15:22:32 +00:00
|
|
|
}
|
|
|
|
}
|
2015-08-26 16:30:15 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename StorageTag>
|
2018-12-27 16:44:19 +00:00
|
|
|
VTKM_CONT void Transfer(const vtkm::cont::ArrayHandle<ValueType, StorageTag>& handle) const
|
2015-11-03 15:22:32 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
//make a buffer for the handle if the user has forgotten too
|
|
|
|
if (!glIsBuffer(*this->State.GetHandle()))
|
|
|
|
{
|
|
|
|
glGenBuffers(1, this->State.GetHandle());
|
|
|
|
}
|
2015-08-26 16:30:15 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
//bind the buffer to the given buffer type
|
|
|
|
glBindBuffer(this->State.GetType(), *this->State.GetHandle());
|
|
|
|
|
|
|
|
//transfer the data.
|
|
|
|
//the primary concern that we have at this point is data locality and
|
2017-10-27 14:42:22 +00:00
|
|
|
//the type of storage. Our options include using DeviceAdapterAlgorithm::Copy
|
|
|
|
//and provide a temporary location for the values to reside before we give it
|
|
|
|
//to openGL this works for all storage types.
|
2017-05-18 14:29:41 +00:00
|
|
|
//
|
|
|
|
//Second option is to call PrepareForInput and get a PortalConst in the
|
2018-01-30 00:24:31 +00:00
|
|
|
//execution environment.
|
2017-05-18 14:29:41 +00:00
|
|
|
//if we are StorageTagBasic this would allow us the ability to grab
|
|
|
|
//the raw memory value and copy those, which we know are valid and remove
|
|
|
|
//a unneeded copy.
|
|
|
|
//
|
|
|
|
//The end result is that we have CopyFromHandle which does number two
|
2017-10-27 14:42:22 +00:00
|
|
|
//from StorageTagBasic, and does the DeviceAdapterAlgorithm::Copy for everything
|
|
|
|
//else
|
2017-05-18 14:29:41 +00:00
|
|
|
detail::CopyFromHandle(handle, this->State, DeviceAdapterTag());
|
2015-08-26 16:30:15 +00:00
|
|
|
}
|
2017-05-18 14:29:41 +00:00
|
|
|
|
2015-08-26 16:30:15 +00:00
|
|
|
private:
|
2016-04-13 19:52:15 +00:00
|
|
|
vtkm::interop::BufferState& State;
|
2015-08-26 16:30:15 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2016-04-13 19:52:15 +00:00
|
|
|
} //namespace vtkm::interop::internal
|
2015-08-26 16:30:15 +00:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// These includes are intentionally placed here after the declaration of the
|
|
|
|
// TransferToOpenGL class, so that people get the correct device adapter
|
|
|
|
/// specializations if they exist.
|
|
|
|
#if VTKM_DEVICE_ADAPTER == VTKM_DEVICE_ADAPTER_CUDA
|
2016-04-13 19:52:15 +00:00
|
|
|
#include <vtkm/interop/cuda/internal/TransferToOpenGL.h>
|
2015-08-26 16:30:15 +00:00
|
|
|
#endif
|
|
|
|
|
2016-04-13 19:52:15 +00:00
|
|
|
#endif //vtk_m_interop_internal_TransferToOpenGL_h
|