b3OpenCLArray.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #ifndef B3_OPENCL_ARRAY_H
  2. #define B3_OPENCL_ARRAY_H
  3. #include "Bullet3Common/b3AlignedObjectArray.h"
  4. #include "Bullet3OpenCL/Initialize/b3OpenCLInclude.h"
  5. template <typename T>
  6. class b3OpenCLArray
  7. {
  8. size_t m_size;
  9. size_t m_capacity;
  10. cl_mem m_clBuffer;
  11. cl_context m_clContext;
  12. cl_command_queue m_commandQueue;
  13. bool m_ownsMemory;
  14. bool m_allowGrowingCapacity;
  15. void deallocate()
  16. {
  17. if (m_clBuffer && m_ownsMemory)
  18. {
  19. clReleaseMemObject(m_clBuffer);
  20. }
  21. m_clBuffer = 0;
  22. m_capacity=0;
  23. }
  24. b3OpenCLArray<T>& operator=(const b3OpenCLArray<T>& src);
  25. B3_FORCE_INLINE size_t allocSize(size_t size)
  26. {
  27. return (size ? size*2 : 1);
  28. }
  29. public:
  30. b3OpenCLArray(cl_context ctx, cl_command_queue queue, size_t initialCapacity=0, bool allowGrowingCapacity=true)
  31. :m_size(0), m_capacity(0),m_clBuffer(0),
  32. m_clContext(ctx),m_commandQueue(queue),
  33. m_ownsMemory(true),m_allowGrowingCapacity(true)
  34. {
  35. if (initialCapacity)
  36. {
  37. reserve(initialCapacity);
  38. }
  39. m_allowGrowingCapacity = allowGrowingCapacity;
  40. }
  41. ///this is an error-prone method with no error checking, be careful!
  42. void setFromOpenCLBuffer(cl_mem buffer, size_t sizeInElements)
  43. {
  44. deallocate();
  45. m_ownsMemory = false;
  46. m_allowGrowingCapacity = false;
  47. m_clBuffer = buffer;
  48. m_size = sizeInElements;
  49. m_capacity = sizeInElements;
  50. }
  51. // we could enable this assignment, but need to make sure to avoid accidental deep copies
  52. // b3OpenCLArray<T>& operator=(const b3AlignedObjectArray<T>& src)
  53. // {
  54. // copyFromArray(src);
  55. // return *this;
  56. // }
  57. cl_mem getBufferCL() const
  58. {
  59. return m_clBuffer;
  60. }
  61. virtual ~b3OpenCLArray()
  62. {
  63. deallocate();
  64. m_size=0;
  65. m_capacity=0;
  66. }
  67. B3_FORCE_INLINE bool push_back(const T& _Val,bool waitForCompletion=true)
  68. {
  69. bool result = true;
  70. size_t sz = size();
  71. if( sz == capacity() )
  72. {
  73. result = reserve( allocSize(size()) );
  74. }
  75. copyFromHostPointer(&_Val, 1, sz, waitForCompletion);
  76. m_size++;
  77. return result;
  78. }
  79. B3_FORCE_INLINE T forcedAt(size_t n) const
  80. {
  81. b3Assert(n>=0);
  82. b3Assert(n<capacity());
  83. T elem;
  84. copyToHostPointer(&elem,1,n,true);
  85. return elem;
  86. }
  87. B3_FORCE_INLINE T at(size_t n) const
  88. {
  89. b3Assert(n>=0);
  90. b3Assert(n<size());
  91. T elem;
  92. copyToHostPointer(&elem,1,n,true);
  93. return elem;
  94. }
  95. B3_FORCE_INLINE bool resize(size_t newsize, bool copyOldContents=true)
  96. {
  97. bool result = true;
  98. size_t curSize = size();
  99. if (newsize < curSize)
  100. {
  101. //leave the OpenCL memory for now
  102. } else
  103. {
  104. if (newsize > size())
  105. {
  106. result = reserve(newsize,copyOldContents);
  107. }
  108. //leave new data uninitialized (init in debug mode?)
  109. //for (size_t i=curSize;i<newsize;i++) ...
  110. }
  111. if (result)
  112. {
  113. m_size = newsize;
  114. } else
  115. {
  116. m_size = 0;
  117. }
  118. return result;
  119. }
  120. B3_FORCE_INLINE size_t size() const
  121. {
  122. return m_size;
  123. }
  124. B3_FORCE_INLINE size_t capacity() const
  125. {
  126. return m_capacity;
  127. }
  128. B3_FORCE_INLINE bool reserve(size_t _Count, bool copyOldContents=true)
  129. {
  130. bool result=true;
  131. // determine new minimum length of allocated storage
  132. if (capacity() < _Count)
  133. { // not enough room, reallocate
  134. if (m_allowGrowingCapacity)
  135. {
  136. cl_int ciErrNum;
  137. //create a new OpenCL buffer
  138. size_t memSizeInBytes = sizeof(T)*_Count;
  139. cl_mem buf = clCreateBuffer(m_clContext, CL_MEM_READ_WRITE, memSizeInBytes, NULL, &ciErrNum);
  140. if (ciErrNum!=CL_SUCCESS)
  141. {
  142. b3Error("OpenCL out-of-memory\n");
  143. _Count = 0;
  144. result = false;
  145. }
  146. //#define B3_ALWAYS_INITIALIZE_OPENCL_BUFFERS
  147. #ifdef B3_ALWAYS_INITIALIZE_OPENCL_BUFFERS
  148. unsigned char* src = (unsigned char*)malloc(memSizeInBytes);
  149. for (size_t i=0;i<memSizeInBytes;i++)
  150. src[i] = 0xbb;
  151. ciErrNum = clEnqueueWriteBuffer( m_commandQueue, buf, CL_TRUE, 0, memSizeInBytes, src, 0,0,0 );
  152. b3Assert(ciErrNum==CL_SUCCESS);
  153. clFinish(m_commandQueue);
  154. free(src);
  155. #endif //B3_ALWAYS_INITIALIZE_OPENCL_BUFFERS
  156. if (result)
  157. {
  158. if (copyOldContents)
  159. copyToCL(buf, size());
  160. }
  161. //deallocate the old buffer
  162. deallocate();
  163. m_clBuffer = buf;
  164. m_capacity = _Count;
  165. } else
  166. {
  167. //fail: assert and
  168. b3Assert(0);
  169. deallocate();
  170. result=false;
  171. }
  172. }
  173. return result;
  174. }
  175. void copyToCL(cl_mem destination, size_t numElements, size_t firstElem=0, size_t dstOffsetInElems=0) const
  176. {
  177. if (numElements<=0)
  178. return;
  179. b3Assert(m_clBuffer);
  180. b3Assert(destination);
  181. //likely some error, destination is same as source
  182. b3Assert(m_clBuffer != destination);
  183. b3Assert((firstElem+numElements)<=m_size);
  184. cl_int status = 0;
  185. b3Assert(numElements>0);
  186. b3Assert(numElements<=m_size);
  187. size_t srcOffsetBytes = sizeof(T)*firstElem;
  188. size_t dstOffsetInBytes = sizeof(T)*dstOffsetInElems;
  189. status = clEnqueueCopyBuffer( m_commandQueue, m_clBuffer, destination,
  190. srcOffsetBytes, dstOffsetInBytes, sizeof(T)*numElements, 0, 0, 0 );
  191. b3Assert( status == CL_SUCCESS );
  192. }
  193. void copyFromHost(const b3AlignedObjectArray<T>& srcArray, bool waitForCompletion=true)
  194. {
  195. size_t newSize = srcArray.size();
  196. bool copyOldContents = false;
  197. resize (newSize,copyOldContents);
  198. if (newSize)
  199. copyFromHostPointer(&srcArray[0],newSize,0,waitForCompletion);
  200. }
  201. void copyFromHostPointer(const T* src, size_t numElems, size_t destFirstElem= 0, bool waitForCompletion=true)
  202. {
  203. b3Assert(numElems+destFirstElem <= capacity());
  204. if (numElems+destFirstElem)
  205. {
  206. cl_int status = 0;
  207. size_t sizeInBytes=sizeof(T)*numElems;
  208. status = clEnqueueWriteBuffer( m_commandQueue, m_clBuffer, 0, sizeof(T)*destFirstElem, sizeInBytes,
  209. src, 0,0,0 );
  210. b3Assert(status == CL_SUCCESS );
  211. if (waitForCompletion)
  212. clFinish(m_commandQueue);
  213. } else
  214. {
  215. b3Error("copyFromHostPointer invalid range\n");
  216. }
  217. }
  218. void copyToHost(b3AlignedObjectArray<T>& destArray, bool waitForCompletion=true) const
  219. {
  220. destArray.resize(this->size());
  221. if (size())
  222. copyToHostPointer(&destArray[0], size(),0,waitForCompletion);
  223. }
  224. void copyToHostPointer(T* destPtr, size_t numElem, size_t srcFirstElem=0, bool waitForCompletion=true) const
  225. {
  226. b3Assert(numElem+srcFirstElem <= capacity());
  227. if(numElem+srcFirstElem <= capacity())
  228. {
  229. cl_int status = 0;
  230. status = clEnqueueReadBuffer( m_commandQueue, m_clBuffer, 0, sizeof(T)*srcFirstElem, sizeof(T)*numElem,
  231. destPtr, 0,0,0 );
  232. b3Assert( status==CL_SUCCESS );
  233. if (waitForCompletion)
  234. clFinish(m_commandQueue);
  235. } else
  236. {
  237. b3Error("copyToHostPointer invalid range\n");
  238. }
  239. }
  240. void copyFromOpenCLArray(const b3OpenCLArray& src)
  241. {
  242. size_t newSize = src.size();
  243. resize(newSize);
  244. if (size())
  245. {
  246. src.copyToCL(m_clBuffer,size());
  247. }
  248. }
  249. };
  250. #endif //B3_OPENCL_ARRAY_H