Voxel
 All Classes Namespaces Files Functions Typedefs Enumerations Enumerator Macros Pages
synchronized_heap_opencl.h
1 #pragma once
2 
3 #ifndef SYNCHRONIZED_HEAP_OPENCL_H
4 #define SYNCHRONIZED_HEAP_OPENCL_H
5 
6 
7 
8 
9 #include "settings.h"
10 
11 
12 
13 
14 #if ( SETTING_OPENCL != 0 )
15 
16 
17 
18 
19 #include "synchronized_heap_base.h"
20 #include "platform.h"
21 #include "opencl.h"
22 #include "exception.h"
23 
24 #include <boost/bimap.hpp>
25 #include <boost/bimap/multiset_of.hpp>
26 #include <boost/bimap/set_of.hpp>
27 
28 #include <unordered_set>
29 #include <memory>
30 
31 #include <CL/cl.h>
32 
33 
34 
35 
36 namespace Synchronized {
37 
38 
39 
40 
41 /*==============================================================================
42  Heap< PLATFORM_OPENCL > specialization
43 ==============================================================================*/
44 
45 
46 template<>
47 struct Heap< PLATFORM_OPENCL > {
48 
49  template< typename t_Type >
50  struct Pointer;
51 
52  typedef cl_mem OpenCLType;
53 
54 
55  inline Heap( std::shared_ptr< OpenCL::State > const& pState, size_t const size );
56 
57 
58  template< typename t_Type >
59  inline Pointer< t_Type > Allocate();
60 
61  template< typename t_Type >
62  inline Pointer< t_Type[] > Allocate( size_t const count );
63 
64 
65  inline void Synchronize();
66 
67 
68  inline OpenCLType OpenCLConvert() const;
69 
70 
71 private:
72 
73  struct ObjectBase {
74 
75  inline ObjectBase( Heap* const pParent, std::pair< size_t, size_t > const& span );
76 
77  virtual ~ObjectBase() = 0;
78 
79 
80  virtual void OpenCLWrite( void* const destination ) const = 0;
81 
82 
83  inline unsigned int References() const;
84 
85  inline void AddReference();
86  inline void ReleaseReference();
87 
88 
89  inline std::pair< size_t, size_t > const& Span() const;
90 
91  inline void Mark() const;
92 
93 
94  private:
95 
96  unsigned int m_refcount;
97 
98  Heap* m_pParent;
99  std::pair< size_t, size_t > m_span;
100  };
101 
102  template< typename t_Type >
103  struct Object : public ObjectBase {
104 
105  typedef t_Type Type;
106 
107 
108  inline Object( Heap* const pParent, std::pair< size_t, size_t > const& span );
109 
110  virtual ~Object();
111 
112 
113  virtual void OpenCLWrite( void* const destination ) const;
114 
115 
116  inline t_Type const* Get() const;
117  inline void Set( t_Type const& value );
118 
119 
120  private:
121 
122  t_Type m_data;
123  };
124 
125  template< typename t_Type >
126  struct Object< t_Type[] > : public ObjectBase {
127 
128  typedef t_Type Type;
129 
130 
131  inline Object( Heap* const pParent, std::pair< size_t, size_t > const& span, size_t const count );
132 
133  virtual ~Object();
134 
135 
136  virtual void OpenCLWrite( void* const destination ) const;
137 
138 
139  inline t_Type const* Get( size_t const index = 0 ) const;
140  inline void Set( size_t const index, t_Type const& value );
141 
142 
143  private:
144 
145  size_t m_count;
146  t_Type* m_array;
147  };
148 
149 
150 public:
151 
152  template< typename t_Type >
153  struct Pointer {
154 
155  typedef typename Object< t_Type >::Type const element_type;
156  typedef cl_uint OpenCLType;
157 
158 
159  inline Pointer();
160  inline Pointer( Pointer const& other );
161 
162  inline ~Pointer();
163 
164 
165  inline void reset();
166  inline void swap( Pointer& other );
167 
168  inline unsigned int use_count() const;
169  inline bool unique() const;
170 
171 
172  inline element_type* get() const;
173 
174  inline void Assign( element_type const& data ) const;
175  inline void Assign( size_t const index, element_type const& data ) const;
176 
177 
178  inline Pointer const& operator=( Pointer const& other );
179 
180 
181  inline operator bool() const;
182 
183  inline element_type* operator->() const;
184  inline element_type& operator*() const;
185 
186  inline element_type& operator[]( size_t const index ) const;
187 
188  inline bool operator==( Pointer const& other ) const;
189  inline bool operator!=( Pointer const& other ) const;
190 
191 
192  inline OpenCLType OpenCLConvert() const;
193 
194 
195  private:
196 
197  inline Pointer( Object< t_Type >* pointer );
198 
199 
200  Object< t_Type >* m_pointer;
201 
202 
203  friend struct Heap< PLATFORM_OPENCL >;
204  };
205 
206 
207 private:
208 
209  struct ObjectComparison {
210 
211  inline bool operator()( ObjectBase const* const pLeft, ObjectBase const* const pRight ) const;
212  };
213 
214 
215  template< typename t_Type >
216  inline std::pair< size_t, size_t > AllocateSpan( size_t const count = 1 );
217 
218  inline void FreeObject( ObjectBase const* pObject );
219 
220  inline void MarkObject( ObjectBase const* pObject );
221 
222 
223  typedef boost::bimap< boost::bimaps::set_of< size_t >, boost::bimaps::multiset_of< size_t > > FreeSpans;
224  typedef std::unordered_set< ObjectBase const* > MarkedObjects;
225 
226 
227  std::shared_ptr< OpenCL::State > m_pState;
228  std::unique_ptr< _cl_mem, OpenCL::Deleter< _cl_mem > > m_buffer;
229 
230  FreeSpans m_freeSpans;
231  MarkedObjects m_markedObjects;
232 };
233 
234 
235 
236 
237 /*==============================================================================
238  Heap< PLATFORM_OPENCL >::ObjectBase methods
239 ==============================================================================*/
240 
241 
242 Heap< PLATFORM_OPENCL >::ObjectBase::ObjectBase( Heap* const pParent, std::pair< size_t, size_t > const& span ) :
243  m_refcount( 0 ),
244  m_pParent( pParent ),
245  m_span( span )
246 {
247 }
248 
249 
250 unsigned int Heap< PLATFORM_OPENCL >::ObjectBase::References() const {
251 
252  return m_refcount;
253 }
254 
255 
256 void Heap< PLATFORM_OPENCL >::ObjectBase::AddReference() {
257 
258  ++m_refcount;
259 }
260 
261 
262 void Heap< PLATFORM_OPENCL >::ObjectBase::ReleaseReference() {
263 
264  assert( m_refcount > 0 );
265  if ( --m_refcount == 0 )
266  delete this;
267 }
268 
269 
270 std::pair< size_t, size_t > const& Heap< PLATFORM_OPENCL >::ObjectBase::Span() const {
271 
272  return m_span;
273 }
274 
275 
276 void Heap< PLATFORM_OPENCL >::ObjectBase::Mark() const {
277 
278  assert( m_pParent != NULL );
279  m_pParent->MarkObject( this );
280 }
281 
282 
283 
284 
285 /*==============================================================================
286  Heap< PLATFORM_OPENCL >::Object methods
287 ==============================================================================*/
288 
289 
290 template< typename t_Type >
291 Heap< PLATFORM_OPENCL >::Object< t_Type >::Object( Heap* const pParent, std::pair< size_t, size_t > const& span ) :
292  ObjectBase( pParent, span )
293 {
294 }
295 
296 
297 template< typename t_Type >
298 Heap< PLATFORM_OPENCL >::Object< t_Type >::~Object() {
299 }
300 
301 
302 template< typename t_Type >
303 void Heap< PLATFORM_OPENCL >::Object< t_Type >::OpenCLWrite( void* const destination ) const {
304 
305  typedef typename OpenCL::Converter< t_Type >::Type OpenCLType;
306  *reinterpret_cast< OpenCLType* >( destination ) = OpenCL::Converter< t_Type >::Convert( m_data );
307 }
308 
309 
310 template< typename t_Type >
311 t_Type const* Heap< PLATFORM_OPENCL >::Object< t_Type >::Get() const {
312 
313  return &m_data;
314 }
315 
316 
317 template< typename t_Type >
318 void Heap< PLATFORM_OPENCL >::Object< t_Type >::Set( t_Type const& data ) {
319 
320  m_data = data;
321  Mark();
322 }
323 
324 
325 template< typename t_Type >
326 Heap< PLATFORM_OPENCL >::Object< t_Type[] >::Object( Heap* const pParent, std::pair< size_t, size_t > const& span, size_t const count ) :
327  ObjectBase( pParent, span ),
328  m_count( count ),
329  m_array( new t_Type[ m_count ] )
330 {
331 }
332 
333 
334 template< typename t_Type >
335 Heap< PLATFORM_OPENCL >::Object< t_Type[] >::~Object() {
336 
337  delete[] m_array;
338 }
339 
340 
341 template< typename t_Type >
342 void Heap< PLATFORM_OPENCL >::Object< t_Type[] >::OpenCLWrite( void* const destination ) const {
343 
344  typedef typename OpenCL::Converter< t_Type >::Type OpenCLType;
345 
346  OpenCLType* ii = reinterpret_cast< OpenCLType* >( destination );
347  OpenCLType* iiEnd = ii + m_count;
348  t_Type const* jj = m_array;
349  for ( ; ii != iiEnd; ++ii, ++jj )
351 }
352 
353 
354 template< typename t_Type >
355 t_Type const* Heap< PLATFORM_OPENCL >::Object< t_Type[] >::Get( size_t const index ) const {
356 
357  assert( index < m_count );
358  return( m_array + index );
359 }
360 
361 
362 template< typename t_Type >
363 void Heap< PLATFORM_OPENCL >::Object< t_Type[] >::Set( size_t const index, t_Type const& data ) {
364 
365  assert( index < m_count );
366  m_array[ index ] = data;
367  Mark();
368 }
369 
370 
371 
372 
373 /*==============================================================================
374  Heap< PLATFORM_OPENCL >::Pointer methods
375 ==============================================================================*/
376 
377 
378 template< typename t_Type >
379 Heap< PLATFORM_OPENCL >::Pointer< t_Type >::Pointer() : m_pointer( NULL ) {
380 }
381 
382 
383 template< typename t_Type >
384 Heap< PLATFORM_OPENCL >::Pointer< t_Type >::Pointer( Pointer const& other ) : m_pointer( other.m_pointer ) {
385 
386  if ( m_pointer != NULL )
387  m_pointer->AddReference();
388 }
389 
390 
391 template< typename t_Type >
392 Heap< PLATFORM_OPENCL >::Pointer< t_Type >::~Pointer() {
393 
394  reset();
395 }
396 
397 
398 template< typename t_Type >
399 void Heap< PLATFORM_OPENCL >::Pointer< t_Type >::reset() {
400 
401  if ( m_pointer != NULL ) {
402 
403  m_pointer->ReleaseReference();
404  m_pointer = NULL;
405  }
406 }
407 
408 
409 template< typename t_Type >
410 void Heap< PLATFORM_OPENCL >::Pointer< t_Type >::swap( Pointer& other ) {
411 
412  std::swap( m_pointer, other.m_pointer );
413 }
414 
415 
416 template< typename t_Type >
417 unsigned int Heap< PLATFORM_OPENCL >::Pointer< t_Type >::use_count() const {
418 
419  unsigned int result = 0;
420  if ( m_pointer != NULL )
421  result = m_pointer->References();
422  return result;
423 }
424 
425 
426 template< typename t_Type >
427 bool Heap< PLATFORM_OPENCL >::Pointer< t_Type >::unique() const {
428 
429  return( use_count() == 1 );
430 }
431 
432 
433 template< typename t_Type >
434 typename Heap< PLATFORM_OPENCL >::Object< t_Type >::Type const* Heap< PLATFORM_OPENCL >::Pointer< t_Type >::get() const {
435 
436  return m_pointer->Get();
437 }
438 
439 
440 template< typename t_Type >
441 void Heap< PLATFORM_OPENCL >::Pointer< t_Type >::Assign( element_type const& data ) const {
442 
443  m_pointer->Set( data );
444 }
445 
446 
447 template< typename t_Type >
448 void Heap< PLATFORM_OPENCL >::Pointer< t_Type >::Assign( size_t const index, element_type const& data ) const {
449 
450  m_pointer->Set( index, data );
451 }
452 
453 
454 template< typename t_Type >
455 Heap< PLATFORM_OPENCL >::Pointer< t_Type > const& Heap< PLATFORM_OPENCL >::Pointer< t_Type >::operator=( Pointer const& other ) {
456 
457  if ( m_pointer != other.m_pointer ) {
458 
459  reset();
460  m_pointer = other.m_pointer;
461  if ( m_pointer != NULL )
462  m_pointer->AddReference();
463  }
464 
465  return *this;
466 }
467 
468 
469 template< typename t_Type >
470 Heap< PLATFORM_OPENCL >::Pointer< t_Type >::operator bool() const {
471 
472  return( m_pointer != NULL );
473 }
474 
475 
476 template< typename t_Type >
477 typename Heap< PLATFORM_OPENCL >::Object< t_Type >::Type const* Heap< PLATFORM_OPENCL >::Pointer< t_Type >::operator->() const {
478 
479  return m_pointer->Get();
480 }
481 
482 
483 template< typename t_Type >
484 typename Heap< PLATFORM_OPENCL >::Object< t_Type >::Type const& Heap< PLATFORM_OPENCL >::Pointer< t_Type >::operator*() const {
485 
486  return *m_pointer->Get();
487 }
488 
489 
490 template< typename t_Type >
491 typename Heap< PLATFORM_OPENCL >::Object< t_Type >::Type const& Heap< PLATFORM_OPENCL >::Pointer< t_Type >::operator[]( size_t const index ) const {
492 
493  return *m_pointer->Get( index );
494 }
495 
496 
497 template< typename t_Type >
498 bool Heap< PLATFORM_OPENCL >::Pointer< t_Type >::operator==( Pointer const& other ) const {
499 
500  return( m_pointer == other.m_pointer );
501 }
502 
503 
504 template< typename t_Type >
505 bool Heap< PLATFORM_OPENCL >::Pointer< t_Type >::operator!=( Pointer const& other ) const {
506 
507  return( m_pointer != other.m_pointer );
508 }
509 
510 
511 template< typename t_Type >
512 Heap< PLATFORM_OPENCL >::Pointer< t_Type >::Pointer( Object< t_Type >* pointer ) : m_pointer( pointer ) {
513 
514  if ( m_pointer != NULL )
515  m_pointer->AddReference();
516 }
517 
518 
519 template< typename t_Type >
520 typename Heap< PLATFORM_OPENCL >::Pointer< t_Type >::OpenCLType Heap< PLATFORM_OPENCL >::Pointer< t_Type >::OpenCLConvert() const {
521 
522  return( ( m_pointer != NULL ) ? m_pointer->Span().first : OPENCL_NULL );
523 }
524 
525 
526 
527 
528 /*==============================================================================
529  Heap< PLATFORM_OPENCL >::ObjectComparison methods
530 ==============================================================================*/
531 
532 
533 bool Heap< PLATFORM_OPENCL >::ObjectComparison::operator()( ObjectBase const* const pLeft, ObjectBase const* const pRight ) const {
534 
535  assert( ( pLeft != NULL ) && ( pRight != NULL ) );
536  return( pLeft->Span() < pRight->Span() );
537 }
538 
539 
540 
541 
542 /*==============================================================================
543  Heap< PLATFORM_OPENCL > methods
544 ==============================================================================*/
545 
546 
547 Heap< PLATFORM_OPENCL >::Heap( std::shared_ptr< OpenCL::State > const& pState, size_t const size ) : m_pState( pState ) {
548 
549  cl_int result = CL_SUCCESS;
550  m_buffer.reset( clCreateBuffer( m_pState->Context(), CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, size, NULL, &result ) );
551  if ( result != CL_SUCCESS )
552  THROW_OPENCL_EXCEPTION( "clCreateBuffer failed!", result );
553 
554  m_freeSpans.insert( FreeSpans::value_type( 0, size ) );
555 }
556 
557 
558 template< typename t_Type >
559 Heap< PLATFORM_OPENCL >::Pointer< t_Type > Heap< PLATFORM_OPENCL >::Allocate() {
560 
561  std::pair< size_t, size_t > const span = AllocateSpan< t_Type >();
562  Object< t_Type >* pObject = new Object< t_Type >( this, span );
563  MarkObject( pObject );
564  return Pointer< t_Type >( pObject );
565 }
566 
567 
568 template< typename t_Type >
569 Heap< PLATFORM_OPENCL >::Pointer< t_Type[] > Heap< PLATFORM_OPENCL >::Allocate( size_t const count ) {
570 
571  std::pair< size_t, size_t > const span = AllocateSpan< t_Type >( count );
572  Object< t_Type[] >* pObject = new Object< t_Type[] >( this, span, count );
573  MarkObject( pObject );
574  return Pointer< t_Type[] >( pObject );
575 }
576 
577 
578 void Heap< PLATFORM_OPENCL >::Synchronize() {
579 
580  if ( ! m_markedObjects.empty() ) {
581 
582  MarkedObjects::size_type const size = m_markedObjects.size();
583  std::unique_ptr< ObjectBase const* > markedObjects( new ObjectBase const*[ size ] );
584  std::copy( m_markedObjects.begin(), m_markedObjects.end(), markedObjects.get() );
585  std::sort( markedObjects.get(), markedObjects.get() + size, ObjectComparison() );
586 
587  ObjectBase const* const* ii = markedObjects.get();
588  ObjectBase const* const* iiEnd = markedObjects.get() + size;
589  while ( ii != iiEnd ) {
590 
591  ObjectBase const* const* iiNext = ii;
592  std::pair< size_t, size_t > span = ( *ii )->Span();
593  for ( ++iiNext; iiNext != iiEnd; ++iiNext ) {
594 
595  std::pair< size_t, size_t > const spanNext = ( *iiNext )->Span();
596  assert( span.first + span.second <= spanNext.first );
597  if ( span.first + span.second == spanNext.first )
598  span.second += spanNext.second;
599  else
600  break;
601  }
602 
603  cl_int result = CL_SUCCESS;
604  void* const buffer = clEnqueueMapBuffer(
605  m_pState->Queue(),
606  m_buffer.get(),
607  CL_TRUE, // blocking
608  CL_MAP_WRITE,
609  span.first,
610  span.second,
611  0,
612  NULL,
613  NULL,
614  &result
615  );
616  if ( result != CL_SUCCESS )
617  THROW_OPENCL_EXCEPTION( "clEnqueueMapBuffer failed!", result );
618 
619  for ( void* destination = buffer; ii != iiNext; ++ii ) {
620 
621  ( *ii )->OpenCLWrite( destination );
622  destination = reinterpret_cast< uint8_t* >( destination ) + ( *ii )->Span().second;
623  }
624 
625  clEnqueueUnmapMemObject(
626  m_pState->Queue(),
627  m_buffer.get(),
628  buffer,
629  0,
630  NULL,
631  NULL
632  );
633 
634  ii = iiNext;
635  }
636 
637  m_markedObjects.clear();
638  }
639 }
640 
641 
642 Heap< PLATFORM_OPENCL >::OpenCLType Heap< PLATFORM_OPENCL >::OpenCLConvert() const {
643 
644  return m_buffer.get();
645 }
646 
647 
648 template< typename t_Type >
649 std::pair< size_t, size_t > Heap< PLATFORM_OPENCL >::AllocateSpan( size_t const count ) {
650 
651  size_t const size = sizeof( typename OpenCL::Converter< t_Type >::Type ) * count;
652 
653  FreeSpans::right_map::iterator ii = m_freeSpans.right.lower_bound( size );
654  if ( ii == m_freeSpans.right.end() )
655  THROW_EXCEPTION( "out of heap space!" );
656 
657  std::pair< size_t, size_t > span( ii->second, ii->first ); // reversed because this is a right_map
658  m_freeSpans.right.erase( ii );
659 
660  assert( span.second >= size );
661  if ( span.second > size ) {
662 
663  m_freeSpans.insert( FreeSpans::value_type( span.first + size, span.second - size ) );
664  span.second = size;
665  }
666 
667  return span;
668 }
669 
670 
671 void Heap< PLATFORM_OPENCL >::FreeObject( ObjectBase const* pObject ) {
672 
673  m_markedObjects.erase( pObject );
674 
675  { std::pair< size_t, size_t > span = pObject->Span();
676 
677  FreeSpans::left_map::iterator ii = m_freeSpans.left.lower_bound( span.first );
678 
679  if ( ii != m_freeSpans.left.begin() ) {
680 
681  FreeSpans::left_map::iterator iiPrev = ii;
682  --iiPrev;
683 
684  assert( iiPrev->first + iiPrev->second <= span.first );
685  if ( iiPrev->first + iiPrev->second == span.first ) {
686 
687  span.first -= iiPrev->second;
688  span.second += iiPrev->second;
689  m_freeSpans.left.erase( iiPrev );
690  }
691  }
692 
693  if ( ii != m_freeSpans.left.end() ) {
694 
695  assert( span.first + span.second <= ii->first );
696  if ( span.first + span.second == ii->first ) {
697 
698  span.second += ii->second;
699  m_freeSpans.left.erase( ii );
700  }
701  }
702 
703  m_freeSpans.insert( FreeSpans::value_type( span.first, span.second ) );
704  }
705 }
706 
707 
708 void Heap< PLATFORM_OPENCL >::MarkObject( ObjectBase const* pObject ) {
709 
710  m_markedObjects.insert( pObject );
711 }
712 
713 
714 
715 
716 } // namespace Synchronized
717 
718 
719 
720 
721 #endif // SETTING_OPENCL
722 
723 
724 
725 
726 #endif // SYNCHRONIZED_HEAP_OPENCL_H