1 // Boost.uBLAS
2 //
3 // Copyright (c) 2018 Fady Essam
4 // Copyright (c) 2018 Stefan Seefeld
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // (See accompanying file LICENSE_1_0.txt or
8 // copy at http://www.boost.org/LICENSE_1_0.txt)
9 
10 #ifndef boost_numeric_ublas_opencl_matrix_hpp_
11 #define boost_numeric_ublas_opencl_matrix_hpp_
12 
13 #include <boost/numeric/ublas/opencl/library.hpp>
14 #include <boost/numeric/ublas/matrix.hpp>
15 #include <boost/numeric/ublas/functional.hpp>
16 #include <boost/compute/core.hpp>
17 #include <boost/compute/algorithm.hpp>
18 #include <boost/compute/buffer.hpp>
19 
20 namespace boost { namespace numeric { namespace ublas { namespace opencl {
21 
22 class storage;
23 
24 namespace compute = boost::compute;
25 
26 } // namespace opencl
27 
28 template<class T, class L>
29 class matrix<T, L, opencl::storage> : public matrix_container<matrix<T, L, opencl::storage> >
30 {
31   typedef typename boost::compute::buffer_allocator<T>::size_type size_type;
32   typedef L layout_type;
33   typedef matrix<T, L, opencl::storage> self_type;
34 public:
matrix()35   matrix()
36     : matrix_container<self_type>(),
37       size1_(0), size2_(0), data_() , device_()
38   {}
39 
matrix(size_type size1,size_type size2,compute::context c)40   matrix(size_type size1, size_type size2, compute::context c)
41     : matrix_container<self_type>(),
42       size1_(size1), size2_(size2), device_(c.get_device())
43   {
44     compute::buffer_allocator<T> allocator(c);
45     data_ = allocator.allocate(layout_type::storage_size(size1, size2)).get_buffer();
46   }
47 
matrix(size_type size1,size_type size2,T const & value,compute::command_queue & q)48   matrix(size_type size1, size_type size2, T const &value, compute::command_queue &q)
49     : matrix_container<self_type>(),
50       size1_(size1), size2_(size2), device_(q.get_device())
51   {
52     compute::buffer_allocator<T> allocator(q.get_context());
53     data_ = allocator.allocate(layout_type::storage_size(size1, size2)).get_buffer();
54     compute::fill(this->begin(), this->end(), value, q);
55     q.finish();
56   }
57 
58   template <typename A>
matrix(matrix<T,L,A> const & m,compute::command_queue & queue)59   matrix(matrix<T, L, A> const &m, compute::command_queue &queue)
60     : matrix(m.size1(), m.size2(), queue.get_context())
61   {
62     this->from_host(m, queue);
63   }
64 
size1() const65   size_type size1() const { return size1_;}
size2() const66   size_type size2() const { return size2_;}
67 
begin() const68   const compute::buffer_iterator<T> begin() const { return compute::make_buffer_iterator<T>(data_);}
begin()69   compute::buffer_iterator<T> begin() { return compute::make_buffer_iterator<T>(data_);}
70 
end()71   compute::buffer_iterator<T> end() { return compute::make_buffer_iterator<T>(data_, layout_type::storage_size(size1_, size2_));}
end() const72   const compute::buffer_iterator<T> end() const { return compute::make_buffer_iterator<T>(data_, layout_type::storage_size(size1_, size2_));}
73 
device() const74   const compute::device &device() const { return device_;}
device()75   compute::device &device() { return device_;}
76 
fill(T value,compute::command_queue & queue)77   void fill(T value, compute::command_queue &queue)
78   {
79     assert(device_ == queue.get_device());
80     compute::fill(this->begin(), this->end(), value, queue);
81     queue.finish();
82   }
83 
84   /** Copies a matrix to a device
85   * \param m is a matrix that is not on the device _device and it is copied to it
86   * \param queue is the command queue that will execute the operation
87   */
88   template<class A>
from_host(ublas::matrix<T,L,A> const & m,compute::command_queue & queue)89   void from_host(ublas::matrix<T, L, A> const &m, compute::command_queue &queue)
90   {
91     assert(device_ == queue.get_device());
92     compute::copy(m.data().begin(),
93 		  m.data().end(),
94 		  this->begin(),
95 		  queue);
96     queue.finish();
97   }
98 
99   /** Copies a matrix from a device
100   * \param m is a matrix that will be reized to (size1_,size2) and the values of (*this) will be copied in it
101   * \param queue is the command queue that will execute the operation
102   */
103   template<class A>
to_host(ublas::matrix<T,L,A> & m,compute::command_queue & queue) const104   void to_host(ublas::matrix<T, L, A> &m, compute::command_queue &queue) const
105   {
106     assert(device_ == queue.get_device());
107     compute::copy(this->begin(),
108 		  this->end(),
109 		  m.data().begin(),
110 		  queue);
111     queue.finish();
112   }
113 
114 private:
115   size_type size1_;
116   size_type size2_;
117   compute::buffer data_;
118   compute::device device_;
119 };
120 
121 }}}
122 
123 #endif
124