1 /*=========================================================================
2 *
3 *  Copyright Insight Software Consortium
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at
8 *
9 *         http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 *=========================================================================*/
18 
19 #ifndef itkGPUImage_h
20 #define itkGPUImage_h
21 
22 #include "itkImage.h"
23 #include "itkGPUImageDataManager.h"
24 #include "itkVersion.h"
25 #include "itkObjectFactoryBase.h"
26 
27 namespace itk
28 {
29 /** \class GPUImage
30  *  \brief Templated n-dimensional image class for the GPU.
31  *
32  * Derived from itk Image class to use with GPU image filters.
33  * This class manages both CPU and GPU memory implicitly, and
34  * can be used with non-GPU itk filters as well. Memory transfer
35  * between CPU and GPU is done automatically and implicitly.
36  *
37  * \ingroup ITKGPUCommon
38  */
39 template <typename TPixel, unsigned int VImageDimension = 2>
40 class ITK_TEMPLATE_EXPORT GPUImage : public Image<TPixel,VImageDimension>
41 {
42 public:
43   ITK_DISALLOW_COPY_AND_ASSIGN(GPUImage);
44 
45   using Self = GPUImage;
46   using Superclass = Image<TPixel,VImageDimension>;
47   using Pointer = SmartPointer<Self>;
48   using ConstPointer = SmartPointer<const Self>;
49   using ConstWeakPointer = WeakPointer<const Self>;
50 
51   itkNewMacro(Self);
52 
53   itkTypeMacro(GPUImage, Image);
54 
55   static constexpr unsigned int ImageDimension = VImageDimension;
56 
57   using PixelType = typename Superclass::PixelType;
58   using ValueType = typename Superclass::ValueType;
59   using InternalPixelType = typename Superclass::InternalPixelType;
60   using IOPixelType = typename Superclass::IOPixelType;
61   using DirectionType = typename Superclass::DirectionType;
62   using SpacingType = typename Superclass::SpacingType;
63   using PixelContainer = typename Superclass::PixelContainer;
64   using SizeType = typename Superclass::SizeType;
65   using IndexType = typename Superclass::IndexType;
66   using OffsetType = typename Superclass::OffsetType;
67   using RegionType = typename Superclass::RegionType;
68   using PixelContainerPointer = typename PixelContainer::Pointer;
69   using PixelContainerConstPointer = typename PixelContainer::ConstPointer;
70   using AccessorType = typename Superclass::AccessorType;
71 
72   using AccessorFunctorType = DefaultPixelAccessorFunctor< Self >;
73 
74   using NeighborhoodAccessorFunctorType = NeighborhoodAccessorFunctor< Self >;
75   // NeighborhoodAccessorFunctorType;
76 
77   //
78   // Allocate CPU and GPU memory space
79   //
80   void Allocate(bool initialize=false) override;
81 
82   void Initialize() override;
83 
84   void FillBuffer(const TPixel & value);
85 
86   void SetPixel(const IndexType & index, const TPixel & value);
87 
88   const TPixel & GetPixel(const IndexType & index) const;
89 
90   TPixel & GetPixel(const IndexType & index);
91 
92   const TPixel & operator[](const IndexType & index) const;
93 
94   TPixel & operator[](const IndexType & index);
95 
96   /** Explicit synchronize CPU/GPU buffers */
97   void UpdateBuffers();
98 
99   //
100   // Get CPU buffer pointer
101   //
102   TPixel* GetBufferPointer() override;
103 
104   const TPixel * GetBufferPointer() const override;
105 
106   /** Return the Pixel Accessor object */
GetPixelAccessor()107   AccessorType GetPixelAccessor()
108   {
109     m_DataManager->SetGPUBufferDirty();
110     return Superclass::GetPixelAccessor();
111   }
112 
113   /** Return the Pixel Accesor object */
GetPixelAccessor()114   const AccessorType GetPixelAccessor() const
115   {
116     m_DataManager->UpdateCPUBuffer();
117     return Superclass::GetPixelAccessor();
118   }
119 
120   /** Return the NeighborhoodAccessor functor */
GetNeighborhoodAccessor()121   NeighborhoodAccessorFunctorType GetNeighborhoodAccessor()
122   {
123     m_DataManager->SetGPUBufferDirty();
124     //return Superclass::GetNeighborhoodAccessor();
125     return NeighborhoodAccessorFunctorType();
126   }
127 
128   /** Return the NeighborhoodAccessor functor */
GetNeighborhoodAccessor()129   const NeighborhoodAccessorFunctorType GetNeighborhoodAccessor() const
130   {
131     m_DataManager->UpdateCPUBuffer();
132     //return Superclass::GetNeighborhoodAccessor();
133     return NeighborhoodAccessorFunctorType();
134   }
135 
136   void SetPixelContainer(PixelContainer *container);
137 
138   /** Return a pointer to the container. */
GetPixelContainer()139   PixelContainer * GetPixelContainer()
140   {
141     m_DataManager->SetGPUBufferDirty(); return Superclass::GetPixelContainer();
142   }
143 
GetPixelContainer()144   const PixelContainer * GetPixelContainer() const
145   {
146     m_DataManager->UpdateCPUBuffer();
147     return Superclass::GetPixelContainer();
148   }
149 
SetCurrentCommandQueue(int queueid)150   void SetCurrentCommandQueue( int queueid )
151   {
152     m_DataManager->SetCurrentCommandQueue( queueid );
153   }
154 
GetCurrentCommandQueueID()155   int  GetCurrentCommandQueueID() {
156     return m_DataManager->GetCurrentCommandQueueID();
157   }
158 
159   itkGetModifiableObjectMacro(DataManager, GPUImageDataManager< GPUImage >);
160   GPUDataManager * GetGPUDataManager();
161 
162   /* Override DataHasBeenGenerated() in DataObject class.
163    * We need this because CPU time stamp is always bigger
164    * than GPU's. That is because Modified() is called at
165    * the end of each filter in the pipeline so although we
166    * increment GPU's time stamp in GPUGenerateData() the
167    * CPU's time stamp will be increased after that.
168    */
DataHasBeenGenerated()169   void DataHasBeenGenerated() override
170   {
171     Superclass::DataHasBeenGenerated();
172     if( m_DataManager->IsCPUBufferDirty() )
173       {
174       m_DataManager->Modified();
175       }
176   }
177 
178   /** Graft the data and information from one GPUImage to another. */
179   virtual void Graft(const Self *data);
180 
181 protected:
182   void Graft(const DataObject *data) override;
183   GPUImage();
184   ~GPUImage() override;
185   using Superclass::Graft;
186 
187 private:
188   typename GPUImageDataManager< GPUImage >::Pointer m_DataManager;
189 };
190 
191 class ITK_TEMPLATE_EXPORT GPUImageFactory : public itk::ObjectFactoryBase
192 {
193 public:
194   ITK_DISALLOW_COPY_AND_ASSIGN(GPUImageFactory);
195 
196   using Self = GPUImageFactory;
197   using Superclass = itk::ObjectFactoryBase;
198   using Pointer = itk::SmartPointer<Self>;
199   using ConstPointer = itk::SmartPointer<const Self>;
200 
201   /** Class methods used to interface with the registered factories. */
GetITKSourceVersion()202   const char* GetITKSourceVersion() const override {
203     return ITK_SOURCE_VERSION;
204   }
GetDescription()205   const char* GetDescription() const override {
206     return "A Factory for GPUImage";
207   }
208 
209   /** Method for class instantiation. */
210   itkFactorylessNewMacro(Self);
211 
212   /** Run-time type information (and related methods). */
213   itkTypeMacro(GPUImageFactory, itk::ObjectFactoryBase);
214 
215   /** Register one factory of this type  */
RegisterOneFactory()216   static void RegisterOneFactory()
217   {
218     GPUImageFactory::Pointer factory = GPUImageFactory::New();
219 
220     itk::ObjectFactoryBase::RegisterFactory(factory);
221   }
222 
223 private:
224 #define OverrideImageTypeMacro(pt,dm)    this->RegisterOverride( \
225     typeid(itk::Image<pt,dm>).name(), \
226     typeid(itk::GPUImage<pt,dm>).name(), \
227     "GPU Image Override", \
228     true, \
229     itk::CreateObjectFunction<GPUImage<pt,dm> >::New() )
230 
GPUImageFactory()231   GPUImageFactory()
232   {
233     if( IsGPUAvailable() )
234       {
235       // 1/2/3D
236       OverrideImageTypeMacro(unsigned char, 1);
237       OverrideImageTypeMacro(signed char,  1);
238       OverrideImageTypeMacro(int, 1);
239       OverrideImageTypeMacro(unsigned int, 1);
240       OverrideImageTypeMacro(float, 1);
241       OverrideImageTypeMacro(double, 1);
242 
243       OverrideImageTypeMacro(unsigned char, 2);
244       OverrideImageTypeMacro(signed char, 2);
245       OverrideImageTypeMacro(int, 2);
246       OverrideImageTypeMacro(unsigned int, 2);
247       OverrideImageTypeMacro(float, 2);
248       OverrideImageTypeMacro(double, 2);
249 
250       OverrideImageTypeMacro(unsigned char, 3);
251       OverrideImageTypeMacro(signed char, 3);
252       OverrideImageTypeMacro(int, 3);
253       OverrideImageTypeMacro(unsigned int, 3);
254       OverrideImageTypeMacro(float, 3);
255       OverrideImageTypeMacro(double, 3);
256       }
257   }
258 
259 };
260 
261 template <typename T>
262 class ITK_TEMPLATE_EXPORT GPUTraits
263 {
264 public:
265   using Type = T;
266 };
267 
268 template <typename TPixelType, unsigned int NDimension>
269 class ITK_TEMPLATE_EXPORT GPUTraits< Image< TPixelType, NDimension > >
270 {
271 public:
272   using Type = GPUImage<TPixelType,NDimension>;
273 };
274 
275 } // end namespace itk
276 
277 #ifndef ITK_MANUAL_INSTANTIATION
278 #include "itkGPUImage.hxx"
279 #endif
280 
281 #endif
282