mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-16 17:22:55 +00:00
Merge topic 'more_efficient_opengl_interop'
4d270187 Update the opengl interop code to be significantly faster with cuda. Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !261
This commit is contained in:
commit
88a605549e
@ -56,9 +56,10 @@ struct HelloVTKMInterop
|
||||
vtkm::Vec< vtkm::Int32, 2 > Dims;
|
||||
|
||||
GLuint ProgramId;
|
||||
GLuint VBOId;
|
||||
GLuint VAOId;
|
||||
GLuint ColorId;
|
||||
|
||||
vtkm::opengl::BufferState VBOState;
|
||||
vtkm::opengl::BufferState ColorState;
|
||||
|
||||
vtkm::cont::Timer<DeviceAdapter> Timer;
|
||||
|
||||
@ -70,9 +71,9 @@ struct HelloVTKMInterop
|
||||
HelloVTKMInterop(vtkm::Int32 width, vtkm::Int32 height):
|
||||
Dims(256,256),
|
||||
ProgramId(),
|
||||
VBOId(),
|
||||
VAOId(),
|
||||
ColorId(),
|
||||
VBOState(),
|
||||
ColorState(),
|
||||
Timer(),
|
||||
InputData(),
|
||||
InHandle(),
|
||||
@ -119,11 +120,11 @@ struct HelloVTKMInterop
|
||||
glUniformMatrix4fv( unifLoc, 1, GL_FALSE, mvp );
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, this->VBOId);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, *this->VBOState.GetHandle());
|
||||
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, 0 );
|
||||
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, this->ColorId);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, *this->ColorState.GetHandle());
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0 );
|
||||
|
||||
glDrawArrays( GL_POINTS, 0, arraySize );
|
||||
@ -165,8 +166,8 @@ struct HelloVTKMInterop
|
||||
GenerateSurfaceWorklet worklet( t );
|
||||
DispatcherType(worklet).Invoke( this->InHandle, this->OutCoords, this->OutColors );
|
||||
|
||||
vtkm::opengl::TransferToOpenGL( this->OutCoords, this->VBOId, DeviceAdapter() );
|
||||
vtkm::opengl::TransferToOpenGL( this->OutColors, this->ColorId, DeviceAdapter() );
|
||||
vtkm::opengl::TransferToOpenGL( this->OutCoords, this->VBOState, DeviceAdapter() );
|
||||
vtkm::opengl::TransferToOpenGL( this->OutColors, this->ColorState, DeviceAdapter() );
|
||||
|
||||
this->render();
|
||||
if(t > 10)
|
||||
|
188
vtkm/opengl/BufferState.h
Normal file
188
vtkm/opengl/BufferState.h
Normal file
@ -0,0 +1,188 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//
|
||||
// Copyright 2014 Sandia Corporation.
|
||||
// Copyright 2014 UT-Battelle, LLC.
|
||||
// Copyright 2014 Los Alamos National Security.
|
||||
//
|
||||
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
||||
// the U.S. Government retains certain rights in this software.
|
||||
//
|
||||
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
|
||||
// Laboratory (LANL), the U.S. Government retains certain rights in
|
||||
// this software.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_opengl_BufferState_h
|
||||
#define vtk_m_opengl_BufferState_h
|
||||
|
||||
//gl headers needs to be buffer anything to do with buffer's
|
||||
#include <vtkm/opengl/internal/OpenGLHeaders.h>
|
||||
#include <vtkm/opengl/internal/BufferTypePicker.h>
|
||||
|
||||
VTKM_THIRDPARTY_PRE_INCLUDE
|
||||
#include <boost/smart_ptr/scoped_ptr.hpp>
|
||||
VTKM_THIRDPARTY_POST_INCLUDE
|
||||
|
||||
namespace vtkm{
|
||||
namespace opengl{
|
||||
|
||||
|
||||
namespace internal
|
||||
{
|
||||
/// \brief Device backend and opengl interop resources management
|
||||
///
|
||||
/// \c TransferResource manages a context for a given device backend and a
|
||||
/// single OpenGL buffer as efficiently as possible.
|
||||
///
|
||||
/// Default implementation is a no-op
|
||||
class TransferResource
|
||||
{
|
||||
public:
|
||||
virtual ~TransferResource() {}
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Manages the state for transferring an ArrayHandle to opengl.
|
||||
///
|
||||
/// \c BufferState holds all the relevant data information for a given ArrayHandle
|
||||
/// mapping into OpenGL. Reusing the state information for all renders of an
|
||||
/// ArrayHandle will allow for the most efficient interop between backends and
|
||||
/// OpenGL ( especially for CUDA ).
|
||||
///
|
||||
///
|
||||
/// The interop code in vtk-m uses a lazy buffer re-allocation.
|
||||
///
|
||||
class BufferState
|
||||
{
|
||||
public:
|
||||
/// Construct a BufferState using an existing GLHandle
|
||||
BufferState(GLuint& gLHandle):
|
||||
OpenGLHandle(&gLHandle),
|
||||
BufferType(GL_INVALID_VALUE),
|
||||
SizeOfActiveSection(0),
|
||||
CapacityOfBuffer(0),
|
||||
DefaultGLHandle(0),
|
||||
Resource(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
/// Construct a BufferState using an existing GLHandle and type
|
||||
BufferState(GLuint& gLHandle, GLenum type):
|
||||
OpenGLHandle(&gLHandle),
|
||||
BufferType(type),
|
||||
SizeOfActiveSection(0),
|
||||
CapacityOfBuffer(0),
|
||||
DefaultGLHandle(0),
|
||||
Resource(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
BufferState():
|
||||
OpenGLHandle(NULL),
|
||||
BufferType(GL_INVALID_VALUE),
|
||||
SizeOfActiveSection(0),
|
||||
CapacityOfBuffer(0),
|
||||
DefaultGLHandle(0),
|
||||
Resource(NULL)
|
||||
{
|
||||
this->OpenGLHandle = &this->DefaultGLHandle;
|
||||
}
|
||||
|
||||
~BufferState()
|
||||
{
|
||||
//don't delete this as it points to user memory, or stack allocated
|
||||
//memory inside this object instance
|
||||
this->OpenGLHandle = NULL;
|
||||
}
|
||||
|
||||
/// \brief get the OpenGL buffer handle
|
||||
///
|
||||
GLuint* GetHandle() const { return this->OpenGLHandle; }
|
||||
|
||||
/// \brief return if this buffer has a valid OpenGL buffer type
|
||||
///
|
||||
bool HasType() const { return this->BufferType != GL_INVALID_VALUE; }
|
||||
|
||||
/// \brief return what OpenGL buffer type we are bound to
|
||||
///
|
||||
/// will return GL_INVALID_VALUE if we don't have a valid type set
|
||||
GLenum GetType() const { return this->BufferType; }
|
||||
|
||||
/// \brief Set what type of OpenGL buffer type we should bind as
|
||||
///
|
||||
void SetType(GLenum type) { this->BufferType = type; }
|
||||
|
||||
/// \brief deduce the buffer type from the template value type that
|
||||
/// was passed in, and set that as our type
|
||||
///
|
||||
/// Will be GL_ELEMENT_ARRAY_BUFFER for
|
||||
/// vtkm::Int32, vtkm::UInt32, vtkm::Int64, vtkm::UInt64, vtkm::Id, and vtkm::IdComponent
|
||||
/// will be GL_ARRAY_BUFFER for everything else.
|
||||
template<typename T>
|
||||
void DeduceAndSetType(T t)
|
||||
{ this->BufferType = vtkm::opengl::internal::BufferTypePicker(t); }
|
||||
|
||||
/// \brief Get the size of the buffer in bytes
|
||||
///
|
||||
/// Get the size of the active section of the buffer
|
||||
///This will always be <= the capacity of the buffer
|
||||
vtkm::Int64 GetSize() const { return this->SizeOfActiveSection; }
|
||||
|
||||
//Set the size of buffer in bytes
|
||||
//This will always needs to be <= the capacity of the buffer
|
||||
//Note: This call should only be used internally by vtk-m
|
||||
void SetSize(vtkm::Int64 size) { this->SizeOfActiveSection = size; }
|
||||
|
||||
/// \brief Get the capacity of the buffer in bytes
|
||||
///
|
||||
/// The buffers that vtk-m allocate in OpenGL use lazy resizing. This allows
|
||||
/// vtk-m to not have to reallocate a buffer while the size stays the same
|
||||
/// or shrinks. This allows allows the cuda to OpenGL to perform significantly
|
||||
/// better as we than don't need to call cudaGraphicsGLRegisterBuffer as
|
||||
/// often
|
||||
vtkm::Int64 GetCapacity() const { return this->CapacityOfBuffer; }
|
||||
|
||||
// Helper function to compute when we should resize the capacity of the
|
||||
// buffer
|
||||
bool ShouldRealloc(vtkm::Int64 desiredSize) const
|
||||
{
|
||||
const bool haveNotEnoughRoom = this->GetCapacity() < desiredSize;
|
||||
const bool haveTooMuchRoom = this->GetCapacity() > (desiredSize*2);
|
||||
return (haveNotEnoughRoom || haveTooMuchRoom);
|
||||
}
|
||||
|
||||
//Set the capacity of buffer in bytes
|
||||
//The capacity of a buffer can be larger than the active size of buffer
|
||||
//Note: This call should only be used internally by vtk-m
|
||||
void SetCapacity(vtkm::Int64 capacity) { this->CapacityOfBuffer = capacity; }
|
||||
|
||||
//Note: This call should only be used internally by vtk-m
|
||||
vtkm::opengl::internal::TransferResource* GetResource()
|
||||
{ return this->Resource.get(); }
|
||||
|
||||
//Note: This call should only be used internally by vtk-m
|
||||
void SetResource( vtkm::opengl::internal::TransferResource* resource)
|
||||
{ this->Resource.reset(resource); }
|
||||
|
||||
|
||||
private:
|
||||
//explicitly state the BufferState doesn't support copy or move semantics
|
||||
BufferState(const BufferState&);
|
||||
void operator=(const BufferState&);
|
||||
|
||||
GLuint* OpenGLHandle;
|
||||
GLenum BufferType;
|
||||
vtkm::Int64 SizeOfActiveSection; //must be Int64 as size can be over 2billion
|
||||
vtkm::Int64 CapacityOfBuffer; //must be Int64 as size can be over 2billion
|
||||
GLuint DefaultGLHandle;
|
||||
boost::scoped_ptr<vtkm::opengl::internal::TransferResource> Resource;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif //vtk_m_opengl_BufferState_h
|
@ -19,6 +19,7 @@
|
||||
##============================================================================
|
||||
|
||||
set(headers
|
||||
BufferState.h
|
||||
TransferToOpenGL.h
|
||||
)
|
||||
|
||||
|
@ -21,37 +21,21 @@
|
||||
#define vtk_m_opengl_TransferToOpenGL_h
|
||||
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/opengl/BufferState.h>
|
||||
#include <vtkm/opengl/internal/TransferToOpenGL.h>
|
||||
|
||||
namespace vtkm{
|
||||
namespace opengl{
|
||||
/// \brief Manages transferring an ArrayHandle to opengl .
|
||||
///
|
||||
/// \c TransferToOpenGL manages to transfer the contents of an ArrayHandle
|
||||
/// to OpenGL as efficiently as possible. Will return the type of array buffer
|
||||
/// that we have bound the handle too. Will be GL_ELEMENT_ARRAY_BUFFER for
|
||||
/// vtkm::Id, and GL_ARRAY_BUFFER for everything else.
|
||||
///
|
||||
/// This function keeps the buffer as the active buffer of the returned type.
|
||||
///
|
||||
/// This function will throw exceptions if the transfer wasn't possible
|
||||
///
|
||||
template<typename ValueType, class StorageTag, class DeviceAdapterTag>
|
||||
VTKM_CONT_EXPORT
|
||||
GLenum TransferToOpenGL(vtkm::cont::ArrayHandle<ValueType,StorageTag> handle,
|
||||
GLuint& openGLHandle,
|
||||
DeviceAdapterTag)
|
||||
{
|
||||
vtkm::opengl::internal::TransferToOpenGL<ValueType, DeviceAdapterTag> toGL;
|
||||
toGL.Transfer(handle,openGLHandle);
|
||||
return toGL.GetType();
|
||||
}
|
||||
|
||||
|
||||
/// \brief Manages transferring an ArrayHandle to opengl .
|
||||
///
|
||||
/// \c TransferToOpenGL manages to transfer the contents of an ArrayHandle
|
||||
/// to OpenGL as efficiently as possible. Will use the given \p type as how
|
||||
/// to bind the buffer.
|
||||
/// to OpenGL as efficiently as possible. Will use the given \p state to determine
|
||||
/// what buffer handle to use, and the type to bind the buffer handle too.
|
||||
/// If the type of buffer hasn't been determined the transfer will use
|
||||
/// deduceAndSetBufferType to do so. Lastly state also holds on to per backend resources
|
||||
/// that allow for efficient updating to open gl
|
||||
///
|
||||
/// This function keeps the buffer as the active buffer of the input type.
|
||||
///
|
||||
@ -60,12 +44,11 @@ GLenum TransferToOpenGL(vtkm::cont::ArrayHandle<ValueType,StorageTag> handle,
|
||||
template<typename ValueType, class StorageTag, class DeviceAdapterTag>
|
||||
VTKM_CONT_EXPORT
|
||||
void TransferToOpenGL(vtkm::cont::ArrayHandle<ValueType, StorageTag> handle,
|
||||
GLuint& openGLHandle,
|
||||
GLenum type,
|
||||
BufferState& state,
|
||||
DeviceAdapterTag)
|
||||
{
|
||||
vtkm::opengl::internal::TransferToOpenGL<ValueType, DeviceAdapterTag> toGL(type);
|
||||
toGL.Transfer(handle,openGLHandle);
|
||||
vtkm::opengl::internal::TransferToOpenGL<ValueType, DeviceAdapterTag> toGL(state);
|
||||
return toGL.Transfer(handle);
|
||||
}
|
||||
|
||||
}}
|
||||
|
@ -39,6 +39,94 @@ namespace vtkm {
|
||||
namespace opengl {
|
||||
namespace internal {
|
||||
|
||||
/// \brief cuda backend and opengl interop resource management
|
||||
///
|
||||
/// \c TransferResource manages cuda resource binding for a given buffer
|
||||
///
|
||||
///
|
||||
class CudaTransferResource : public vtkm::opengl::internal::TransferResource
|
||||
{
|
||||
public:
|
||||
CudaTransferResource():
|
||||
vtkm::opengl::internal::TransferResource()
|
||||
{
|
||||
this->Registered = false;
|
||||
}
|
||||
|
||||
~CudaTransferResource()
|
||||
{
|
||||
//unregister the buffer
|
||||
if(this->Registered)
|
||||
{
|
||||
cudaGraphicsUnregisterResource(this->CudaResource);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IsRegistered() const { return Registered; }
|
||||
|
||||
void Register(GLuint* handle)
|
||||
{
|
||||
if(this->Registered)
|
||||
{
|
||||
//If you don't release the cuda resource before re-registering you
|
||||
//will leak memory on the OpenGL side.
|
||||
cudaGraphicsUnregisterResource(this->CudaResource);
|
||||
}
|
||||
|
||||
this->Registered = true;
|
||||
cudaError_t cError = cudaGraphicsGLRegisterBuffer(&this->CudaResource,
|
||||
*handle,
|
||||
cudaGraphicsMapFlagsWriteDiscard);
|
||||
if(cError != cudaSuccess)
|
||||
{
|
||||
throw vtkm::cont::ErrorExecution(
|
||||
"Could not register the OpenGL buffer handle to CUDA.");
|
||||
}
|
||||
}
|
||||
|
||||
void Map()
|
||||
{
|
||||
//map the resource into cuda, so we can copy it
|
||||
cudaError_t cError =cudaGraphicsMapResources(1,&this->CudaResource);
|
||||
if(cError != cudaSuccess)
|
||||
{
|
||||
throw vtkm::cont::ErrorControlBadAllocation(
|
||||
"Could not allocate enough memory in CUDA for OpenGL interop.");
|
||||
}
|
||||
}
|
||||
|
||||
template< typename ValueType >
|
||||
ValueType* GetMappedPoiner( vtkm::Int64 desiredSize)
|
||||
{
|
||||
//get the mapped pointer
|
||||
std::size_t cuda_size;
|
||||
ValueType* pointer = NULL;
|
||||
cudaError_t cError = cudaGraphicsResourceGetMappedPointer((void **)&pointer,
|
||||
&cuda_size,
|
||||
this->CudaResource);
|
||||
|
||||
if(cError != cudaSuccess)
|
||||
{
|
||||
throw vtkm::cont::ErrorExecution(
|
||||
"Unable to get pointers to CUDA memory for OpenGL buffer.");
|
||||
}
|
||||
|
||||
//assert that cuda_size is the same size as the buffer we created in OpenGL
|
||||
VTKM_ASSERT_CONT(cuda_size >= desiredSize);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
void UnMap()
|
||||
{
|
||||
cudaGraphicsUnmapResources(1, &this->CudaResource);
|
||||
}
|
||||
|
||||
private:
|
||||
bool Registered;
|
||||
cudaGraphicsResource_t CudaResource;
|
||||
};
|
||||
|
||||
/// \brief Manages transferring an ArrayHandle to opengl .
|
||||
///
|
||||
/// \c TransferToOpenGL manages to transfer the contents of an ArrayHandle
|
||||
@ -49,72 +137,65 @@ class TransferToOpenGL<ValueType, vtkm::cont::DeviceAdapterTagCuda>
|
||||
{
|
||||
typedef vtkm::cont::DeviceAdapterTagCuda DeviceAdapterTag;
|
||||
public:
|
||||
VTKM_CONT_EXPORT TransferToOpenGL():
|
||||
Type( vtkm::opengl::internal::BufferTypePicker( ValueType() ) )
|
||||
{}
|
||||
VTKM_CONT_EXPORT explicit TransferToOpenGL(BufferState& state):
|
||||
State(state),
|
||||
Resource(NULL)
|
||||
{
|
||||
if( !this->State.HasType() )
|
||||
{
|
||||
this->State.DeduceAndSetType( ValueType() );
|
||||
}
|
||||
|
||||
VTKM_CONT_EXPORT explicit TransferToOpenGL(GLenum type):
|
||||
Type(type)
|
||||
{}
|
||||
this->Resource = dynamic_cast<vtkm::opengl::internal::CudaTransferResource*>
|
||||
(state.GetResource());
|
||||
if( !this->Resource )
|
||||
{
|
||||
vtkm::opengl::internal::CudaTransferResource* cudaResource =
|
||||
new vtkm::opengl::internal::CudaTransferResource();
|
||||
|
||||
GLenum GetType() const { return this->Type; }
|
||||
//reset the resource to be a cuda resource
|
||||
this->State.SetResource( cudaResource );
|
||||
this->Resource = cudaResource;
|
||||
}
|
||||
}
|
||||
|
||||
template< typename StorageTag >
|
||||
VTKM_CONT_EXPORT
|
||||
void Transfer (
|
||||
vtkm::cont::ArrayHandle<ValueType, StorageTag> &handle,
|
||||
GLuint& openGLHandle ) const
|
||||
vtkm::cont::ArrayHandle<ValueType, StorageTag> &handle) const
|
||||
{
|
||||
//construct a cuda resource handle
|
||||
cudaGraphicsResource_t cudaResource;
|
||||
cudaError_t cError;
|
||||
|
||||
//make a buffer for the handle if the user has forgotten too
|
||||
if(!glIsBuffer(openGLHandle))
|
||||
{
|
||||
glGenBuffers(1,&openGLHandle);
|
||||
}
|
||||
if(!glIsBuffer(*this->State.GetHandle()))
|
||||
{
|
||||
glGenBuffers(1, this->State.GetHandle());
|
||||
}
|
||||
|
||||
//bind the buffer to the given buffer type
|
||||
glBindBuffer(this->Type, openGLHandle);
|
||||
glBindBuffer(this->State.GetType(), *this->State.GetHandle());
|
||||
|
||||
//Allocate the memory and set it as GL_DYNAMIC_DRAW draw
|
||||
const vtkm::Id size = static_cast<vtkm::Id>(sizeof(ValueType))* handle.GetNumberOfValues();
|
||||
glBufferData(this->Type, size, 0, GL_DYNAMIC_DRAW);
|
||||
//Determine if we need to reallocate the buffer
|
||||
const vtkm::Int64 size = static_cast<vtkm::Int64>(sizeof(ValueType))* handle.GetNumberOfValues();
|
||||
this->State.SetSize(size);
|
||||
const bool resize = this->State.ShouldRealloc(size);
|
||||
if( resize )
|
||||
{
|
||||
//Allocate the memory and set it as GL_DYNAMIC_DRAW draw
|
||||
glBufferData(this->State.GetType(), size, 0, GL_DYNAMIC_DRAW);
|
||||
|
||||
//register the buffer as being used by cuda
|
||||
cError = cudaGraphicsGLRegisterBuffer(&cudaResource,
|
||||
openGLHandle,
|
||||
cudaGraphicsMapFlagsWriteDiscard);
|
||||
if(cError != cudaSuccess)
|
||||
{
|
||||
throw vtkm::cont::ErrorExecution(
|
||||
"Could not register the OpenGL buffer handle to CUDA.");
|
||||
}
|
||||
this->State.SetCapacity(size);
|
||||
}
|
||||
|
||||
//map the resource into cuda, so we can copy it
|
||||
cError =cudaGraphicsMapResources(1,&cudaResource);
|
||||
if(cError != cudaSuccess)
|
||||
{
|
||||
throw vtkm::cont::ErrorControlBadAllocation(
|
||||
"Could not allocate enough memory in CUDA for OpenGL interop.");
|
||||
}
|
||||
if(!this->Resource->IsRegistered() || resize )
|
||||
{
|
||||
//register the buffer as being used by cuda. This needs to be done everytime
|
||||
//we change the size of the buffer. That is why we only change the buffer
|
||||
//size as infrequently as possible
|
||||
this->Resource->Register(this->State.GetHandle());
|
||||
}
|
||||
|
||||
//get the mapped pointer
|
||||
std::size_t cuda_size;
|
||||
ValueType* beginPointer=NULL;
|
||||
cError = cudaGraphicsResourceGetMappedPointer((void **)&beginPointer,
|
||||
&cuda_size,
|
||||
cudaResource);
|
||||
this->Resource->Map();
|
||||
|
||||
if(cError != cudaSuccess)
|
||||
{
|
||||
throw vtkm::cont::ErrorExecution(
|
||||
"Unable to get pointers to CUDA memory for OpenGL buffer.");
|
||||
}
|
||||
|
||||
//assert that cuda_size is the same size as the buffer we created in OpenGL
|
||||
VTKM_ASSERT_CONT(cuda_size == size);
|
||||
ValueType* beginPointer= this->Resource->GetMappedPoiner<ValueType>(size);
|
||||
|
||||
//get the device pointers
|
||||
typedef vtkm::cont::ArrayHandle<ValueType, StorageTag> HandleType;
|
||||
@ -134,14 +215,12 @@ public:
|
||||
thrust::cuda::pointer<ValueType>(beginPointer));
|
||||
|
||||
//unmap the resource
|
||||
cudaGraphicsUnmapResources(1, &cudaResource);
|
||||
|
||||
//unregister the buffer
|
||||
cudaGraphicsUnregisterResource(cudaResource);
|
||||
this->Resource->UnMap();
|
||||
|
||||
}
|
||||
private:
|
||||
GLenum Type;
|
||||
vtkm::opengl::BufferState& State;
|
||||
vtkm::opengl::internal::CudaTransferResource* Resource;
|
||||
};
|
||||
|
||||
|
||||
|
@ -30,10 +30,10 @@ namespace internal {
|
||||
/// helper function that guesses what OpenGL buffer type is the best default
|
||||
/// given a primitive type. Currently GL_ELEMENT_ARRAY_BUFFER is used for integer
|
||||
/// types, and GL_ARRAY_BUFFER is used for everything else
|
||||
VTKM_CONT_EXPORT GLenum BufferTypePicker( int )
|
||||
VTKM_CONT_EXPORT GLenum BufferTypePicker( vtkm::Int32 )
|
||||
{ return GL_ELEMENT_ARRAY_BUFFER; }
|
||||
|
||||
VTKM_CONT_EXPORT GLenum BufferTypePicker( unsigned int )
|
||||
VTKM_CONT_EXPORT GLenum BufferTypePicker( vtkm::UInt32 )
|
||||
{ return GL_ELEMENT_ARRAY_BUFFER; }
|
||||
|
||||
#if VTKM_SIZE_LONG == 8
|
||||
|
@ -25,7 +25,9 @@
|
||||
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
|
||||
|
||||
#include <vtkm/opengl/internal/OpenGLHeaders.h>
|
||||
#include <vtkm/opengl/internal/BufferTypePicker.h>
|
||||
#include <vtkm/opengl/BufferState.h>
|
||||
|
||||
|
||||
namespace vtkm {
|
||||
namespace opengl {
|
||||
namespace internal {
|
||||
@ -37,7 +39,7 @@ template<class ValueType, class StorageTag, class DeviceAdapterTag>
|
||||
VTKM_CONT_EXPORT
|
||||
void CopyFromHandle(
|
||||
vtkm::cont::ArrayHandle<ValueType, StorageTag>& handle,
|
||||
GLenum type,
|
||||
vtkm::opengl::BufferState& state,
|
||||
DeviceAdapterTag)
|
||||
{
|
||||
//Generic implementation that will work no matter what. We copy the data
|
||||
@ -61,11 +63,19 @@ void CopyFromHandle(
|
||||
//Note that the temporary ArrayHandle is no longer valid after this call
|
||||
ValueType* temporaryStorage = tmpHandle.Internals->ControlArray.StealArray();
|
||||
|
||||
//Detach the current buffer
|
||||
glBufferData(type, size, 0, GL_DYNAMIC_DRAW);
|
||||
//Determine if we need to reallocate the buffer
|
||||
state.SetSize(size);
|
||||
const bool resize = state.ShouldRealloc(size);
|
||||
if( resize )
|
||||
{
|
||||
//Allocate the memory and set it as GL_DYNAMIC_DRAW draw
|
||||
glBufferData(state.GetType(), size, 0, GL_DYNAMIC_DRAW);
|
||||
|
||||
//Allocate the memory and set it as static draw and copy into opengl
|
||||
glBufferSubData(type,0,size,temporaryStorage);
|
||||
state.SetCapacity(size);
|
||||
}
|
||||
|
||||
//copy into opengl buffer
|
||||
glBufferSubData(state.GetType(),0,size,temporaryStorage);
|
||||
|
||||
delete[] temporaryStorage;
|
||||
}
|
||||
@ -74,7 +84,7 @@ template<class ValueType, class DeviceAdapterTag>
|
||||
VTKM_CONT_EXPORT
|
||||
void CopyFromHandle(
|
||||
vtkm::cont::ArrayHandle<ValueType, vtkm::cont::StorageTagBasic>& handle,
|
||||
GLenum type,
|
||||
vtkm::opengl::BufferState& state,
|
||||
DeviceAdapterTag)
|
||||
{
|
||||
//Specialization given that we are use an C allocated array storage tag
|
||||
@ -87,13 +97,21 @@ void CopyFromHandle(
|
||||
static_cast<GLsizeiptr>(sizeof(ValueType)) *
|
||||
static_cast<GLsizeiptr>(handle.GetNumberOfValues());
|
||||
|
||||
//Detach the current buffer
|
||||
glBufferData(type, size, 0, GL_DYNAMIC_DRAW);
|
||||
//Determine if we need to reallocate the buffer
|
||||
state.SetSize(size);
|
||||
const bool resize = state.ShouldRealloc(size);
|
||||
if( resize )
|
||||
{
|
||||
//Allocate the memory and set it as GL_DYNAMIC_DRAW draw
|
||||
glBufferData(state.GetType(), size, 0, GL_DYNAMIC_DRAW);
|
||||
|
||||
state.SetCapacity(size);
|
||||
}
|
||||
|
||||
//Allocate the memory and set it as static draw and copy into opengl
|
||||
const ValueType* memory = &(*vtkm::cont::ArrayPortalToIteratorBegin(
|
||||
handle.PrepareForInput(DeviceAdapterTag())));
|
||||
glBufferSubData(type,0,size,memory);
|
||||
glBufferSubData(state.GetType(),0,size,memory);
|
||||
|
||||
}
|
||||
|
||||
@ -108,30 +126,28 @@ template<typename ValueType, class DeviceAdapterTag>
|
||||
class TransferToOpenGL
|
||||
{
|
||||
public:
|
||||
VTKM_CONT_EXPORT TransferToOpenGL():
|
||||
Type( vtkm::opengl::internal::BufferTypePicker( ValueType() ) )
|
||||
{}
|
||||
|
||||
VTKM_CONT_EXPORT explicit TransferToOpenGL(GLenum type):
|
||||
Type(type)
|
||||
{}
|
||||
|
||||
VTKM_CONT_EXPORT GLenum GetType() const { return this->Type; }
|
||||
VTKM_CONT_EXPORT explicit TransferToOpenGL(BufferState& state):
|
||||
State(state)
|
||||
{
|
||||
if( !this->State.HasType() )
|
||||
{
|
||||
this->State.DeduceAndSetType( ValueType() );
|
||||
}
|
||||
}
|
||||
|
||||
template< typename StorageTag >
|
||||
VTKM_CONT_EXPORT
|
||||
void Transfer (
|
||||
vtkm::cont::ArrayHandle<ValueType, StorageTag>& handle,
|
||||
GLuint& openGLHandle ) const
|
||||
vtkm::cont::ArrayHandle<ValueType, StorageTag>& handle) const
|
||||
{
|
||||
//make a buffer for the handle if the user has forgotten too
|
||||
if(!glIsBuffer(openGLHandle))
|
||||
{
|
||||
glGenBuffers(1,&openGLHandle);
|
||||
}
|
||||
if(!glIsBuffer(*this->State.GetHandle()))
|
||||
{
|
||||
glGenBuffers(1, this->State.GetHandle());
|
||||
}
|
||||
|
||||
//bind the buffer to the given buffer type
|
||||
glBindBuffer(this->Type, openGLHandle);
|
||||
glBindBuffer(this->State.GetType(), *this->State.GetHandle());
|
||||
|
||||
//transfer the data.
|
||||
//the primary concern that we have at this point is data locality and
|
||||
@ -147,10 +163,10 @@ public:
|
||||
//
|
||||
//The end result is that we have CopyFromHandle which does number two
|
||||
//from StorageTagBasic, and does the CopyInto for everything else
|
||||
detail::CopyFromHandle(handle, this->Type, DeviceAdapterTag());
|
||||
detail::CopyFromHandle(handle, this->State, DeviceAdapterTag());
|
||||
}
|
||||
private:
|
||||
GLenum Type;
|
||||
vtkm::opengl::BufferState& State;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -75,7 +75,8 @@ private:
|
||||
{
|
||||
try
|
||||
{
|
||||
vtkm::opengl::TransferToOpenGL(array,handle, DeviceAdapterTag());
|
||||
vtkm::opengl::BufferState state(handle);
|
||||
vtkm::opengl::TransferToOpenGL(array, state, DeviceAdapterTag());
|
||||
}
|
||||
catch (vtkm::cont::ErrorControlBadAllocation error)
|
||||
{
|
||||
@ -97,7 +98,8 @@ private:
|
||||
{
|
||||
try
|
||||
{
|
||||
vtkm::opengl::TransferToOpenGL(array,handle,type, DeviceAdapterTag());
|
||||
vtkm::opengl::BufferState state(handle, type);
|
||||
vtkm::opengl::TransferToOpenGL(array, state, DeviceAdapterTag());
|
||||
}
|
||||
catch (vtkm::cont::ErrorControlBadAllocation error)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user