Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkOclImage.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 #include "mitkOclImage.h"
18 #include "mitkImageDataItem.h"
19 #include "mitkCommon.h"
20 #include "mitkLogMacros.h"
21 
22 #include "mitkOclUtils.h"
23 
24 #include <mitkImageReadAccessor.h>
25 #include <fstream>
26 
27 mitk::OclImage::OclImage() : m_gpuImage(NULL), m_context(NULL), m_bufferSize(0), m_gpuModified(false), m_cpuModified(false),
28  m_Image(NULL), m_dim(0), m_Dims(NULL), m_BpE(1), m_formatSupported(false)
29 {
30 }
31 
33 {
34  MITK_INFO << "OclImage Destructor";
35 
36  //release GMEM Image buffer
37  if (m_gpuImage) clReleaseMemObject(m_gpuImage);
38 }
39 
40 
41 cl_mem mitk::OclImage::CreateGPUImage(unsigned int _wi, unsigned int _he, unsigned int _de,
42  unsigned int _bpp)
43 {
44  MITK_INFO << "CreateGPUImage call with: BPP=" << _bpp;
45 
46  this->m_Dims = new unsigned int[MAX_DIMS];
47 
48  m_Dims[0] = _wi;
49  m_Dims[1] = _he;
50  m_Dims[2] = _de;
51 
52  for (unsigned int i=3; i<MAX_DIMS; i++)
53  m_Dims[i] = 1;
54 
55  m_bufferSize = _wi * _he * _de;
56 
57  m_BpE = _bpp;
58 
61 
62  cl_context gpuContext = resources->GetContext();
63 
64  int clErr;
65  m_gpuImage = clCreateBuffer( gpuContext, CL_MEM_READ_WRITE, m_bufferSize * m_BpE, NULL, &clErr);
66 
67  CHECK_OCL_ERR(clErr);
68 
69  return m_gpuImage;
70 }
71 
73 {
74  this->m_Image = _image;
75  this->m_cpuModified = true;
76  this->m_gpuModified = false;
77 
78  this->m_gpuImage = NULL;
79 
80  // compute the size of the GMEM buffer
81  this->m_dim = this->m_Image->GetDimension();
82  this->m_Dims = this->m_Image->GetDimensions();
83  MITK_INFO << "Image: " << this->m_Dims[0] <<"x"<< this->m_Dims[1] <<"x"<< this->m_Dims[2];
84 
85  // get the dimensions
86  this->m_bufferSize = 1;
87  for (unsigned int i=0; i<this->m_dim; i++)
88  {
89  this->m_bufferSize *= this->m_Dims[i];
90  }
91 
92  // multiply by sizeof(PixelType)
93  this->m_BpE = ( this->m_Image->GetPixelType().GetBpe() / 8);
94 }
95 
97 {
98  if (_type) return m_cpuModified;
99  else return m_gpuModified;
100 }
101 
103 {
104  // defines... GPU: 0, CPU: 1
105  m_cpuModified = _type;
106  m_gpuModified = !_type;
107 }
108 
109 int mitk::OclImage::TransferDataToGPU(cl_command_queue gpuComQueue)
110 {
111  cl_int clErr = 0;
112 
113  // check whether an image present
114  if (!m_Image->IsInitialized()){
115  MITK_ERROR("ocl.Image") << "(mitk) Image not initialized!\n";
116  return -1;
117  }
118 
119  // there is a need for copy only if RAM-Data newer then GMEM data
120  if (m_cpuModified)
121  {
122  //check the buffer
123  if(m_gpuImage == NULL)
124  {
125  clErr = this->AllocateGPUImage();
126  }
127 
128  if (m_Image->IsInitialized() &&
129  (clErr == CL_SUCCESS))
130  {
131  const size_t origin[3] = {0, 0, 0};
132  const size_t region[3] = {m_Dims[0], m_Dims[1], m_Dims[2]};
133 
134  if( this->m_formatSupported )
135  {
136  mitk::ImageReadAccessor accessor(m_Image);
137  clErr = clEnqueueWriteImage( gpuComQueue, m_gpuImage, CL_TRUE, origin, region, 0, 0, accessor.GetData(), 0, NULL, NULL);
138  }
139  else
140  {
141  MITK_ERROR << "Selected image format currently not supported...";
142  }
143 
144  CHECK_OCL_ERR(clErr);
145  }
146  m_gpuModified = true;
147  }
148 
149  return clErr;
150 }
151 
152 cl_int mitk::OclImage::AllocateGPUImage()
153 {
154  cl_int clErr = 0;
155 
158 
159  cl_context gpuContext = resources->GetContext();
160 
161  // initialize both proposed and supported format variables to same value
162  this->m_proposedFormat = this->ConvertPixelTypeToOCLFormat();
163  this->m_supportedFormat = this->m_proposedFormat;
164 
165  // test the current format for HW support
166  this->m_formatSupported = resources->GetIsFormatSupported( &(this->m_supportedFormat) );
167 
168  // create an transfer kernel object in case the proposed format is not supported
169  if( !(this->m_formatSupported) )
170  {
171  mitkThrowException(mitk::ImageTypeIsNotSupportedByGPU) << "Original format not supported on the installed graphics card.";
172  }
173 
174  // create new buffer
175  if( this->m_dim > 2)
176  {
177  //Create a 3D Image
178  m_gpuImage = clCreateImage3D(gpuContext, CL_MEM_READ_ONLY, &m_supportedFormat, *(m_Dims), *(m_Dims+1), *(m_Dims+2), 0, 0, NULL, &clErr);
179  }
180  else
181  {
182  //Create a 2D Image
183  m_gpuImage = clCreateImage2D(gpuContext, CL_MEM_READ_ONLY, &m_supportedFormat, *(m_Dims), *(m_Dims+1), 0, NULL, &clErr);
184  }
185  CHECK_OCL_ERR(clErr);
186 
187  return clErr;
188 }
189 
190 cl_mem mitk::OclImage::GetGPUImage(cl_command_queue gpuComQueue)
191 {
192  // clGetMemObjectInfo()
193  cl_mem_object_type memInfo;
194  cl_int clErr = 0;
195 
196  // query image object info only if already initialized
197  if( this->m_gpuImage )
198  {
199  clErr = clGetMemObjectInfo(this->m_gpuImage, CL_MEM_TYPE, sizeof(cl_mem_object_type), &memInfo, NULL );
200  CHECK_OCL_ERR(clErr);
201  }
202 
203  MITK_INFO << "Querying info for object, recieving: " << memInfo;
204 
205  // test if m_gpuImage CL_MEM_IMAGE_2/3D
206  // if not, copy buffer to image
207  if (memInfo == CL_MEM_OBJECT_BUFFER)
208  {
209  MITK_WARN << " Passed oclImage is a buffer-object, creating image";
210 
211  //hold a copy of the buffer gmem pointer
212  cl_mem tempBuffer = this->m_gpuImage;
213 
214  const size_t origin[3] = {0, 0, 0};
215  size_t region[3] = {this->m_Dims[0], this->m_Dims[1], 1};
216 
217  clErr = this->AllocateGPUImage();
218 
219  this->m_dim = 3;
220 
221  //copy last data to the image data
222  clErr = clEnqueueCopyBufferToImage( gpuComQueue, tempBuffer, m_gpuImage, 0, origin, region, 0, NULL, NULL);
223  CHECK_OCL_ERR(clErr);
224 
225  //release pointer
226  clReleaseMemObject(tempBuffer);
227  }
228  return m_gpuImage;
229 }
230 
231 void mitk::OclImage::SetPixelType(const cl_image_format *_image)
232 {
233  this->m_proposedFormat.image_channel_data_type = _image->image_channel_data_type;
234  this->m_proposedFormat.image_channel_order = _image->image_channel_order;
235 }
236 
237 void* mitk::OclImage::TransferDataToCPU(cl_command_queue gpuComQueue)
238 {
239  cl_int clErr = 0;
240 
241  // if image created on GPU, needs to create mitk::Image
242  if( m_Image.IsNull() ){
243  MITK_INFO << "Image not initialized, creating new one.";
244  m_Image = mitk::Image::New();
245  }
246 
247  // check buffersize/image size
248  char* data = new char[m_bufferSize * m_BpE];
249 
250  // debug info
251  oclPrintMemObjectInfo( m_gpuImage );
252 
253  clErr = clEnqueueReadBuffer( gpuComQueue, m_gpuImage, CL_FALSE, 0, m_bufferSize * m_BpE, data ,0, NULL, NULL);
254  CHECK_OCL_ERR(clErr);
255 
256  clFlush( gpuComQueue );
257  // the cpu data is same as gpu
258  this->m_gpuModified = false;
259 
260  return (void*) data;
261 }
262 
263 cl_image_format mitk::OclImage::ConvertPixelTypeToOCLFormat()
264 {
265  cl_image_format texFormat;
266  //single channel Gray-Valued Images
267  texFormat.image_channel_order = CL_R;
268 
269  MITK_INFO << "Class own value: " << this->m_BpE;
270 
271  switch ( this->m_BpE )
272  {
273  case 1:
274  texFormat.image_channel_data_type = CL_UNSIGNED_INT8;
275  MITK_INFO<< "PixelType: UCHAR => CLFormat: [CL_UNORM_INT8, CL_R]";
276  break;
277  case 2:
278  texFormat.image_channel_data_type = CL_SIGNED_INT16;
279  // texFormat.image_channel_order = CL_R;
280  MITK_INFO<< "PixelType: SHORT => CLFormat: [CL_SIGNED_INT16, CL_R]";
281  break;
282  case 4:
283  texFormat.image_channel_data_type = CL_FLOAT;
284  MITK_INFO<< "Choosing CL_FLOAT";
285  break;
286  default:
287  texFormat.image_channel_data_type = CL_UNORM_INT8;
288  texFormat.image_channel_order = CL_RG;
289  MITK_INFO<< "Choosing (default) short: 2-Channel UCHAR";
290  break;
291  }
292 
293  return texFormat;
294 }
295 
297 {
298  if (this->m_dim > idx)
299  {
300  return m_Dims[idx];
301  }
302  else
303  {
304  MITK_WARN << "Trying to access non-existing dimension.";
305  return 1;
306  }
307 }
308 
309 void mitk::OclImage::SetDimensions(unsigned int* Dims)
310 {
311  m_Dims = Dims;
312 }
313 
314 void mitk::OclImage::SetDimension(unsigned short dim)
315 {
316  m_dim = dim;
317 }
318 
320 {
321  if (this->m_dim > idx)
322  {
323  const mitk::Vector3D imSpacing = m_Image->GetSlicedGeometry()->GetSpacing();
324 
325  return imSpacing[idx];
326  }
327  else
328  {
329  MITK_WARN << "Trying to access non-existing dimension.";
330  return 1;
331  }
332 }
333 
335 {
336  this->m_Image = mitk::Image::New();
337 }
338 
339 void mitk::OclImage::GetOffset(float* _imOffset) const
340 {
341  itk::Vector<float, 3> result2;
342  result2.Fill(0.0f);
343 
344  result2 = this->m_Image->GetGeometry()->GetIndexToWorldTransform()->GetOffset();
345 
346  _imOffset[0] = result2[0];
347  _imOffset[1] = result2[1];
348  _imOffset[2] = result2[2];
349 }
#define CHECK_OCL_ERR(_er)
Definition: mitkOclUtils.h:25
virtual ~OclImage()
Destructor.
ServiceReferenceU GetServiceReference(const std::string &clazz)
cl_mem CreateGPUImage(unsigned int, unsigned int, unsigned int, unsigned int)
#define MITK_INFO
Definition: mitkLogMacros.h:22
cl_mem GetGPUImage(cl_command_queue)
Checks whether gpuImage is a valid clImage object.
#define MITK_ERROR
Definition: mitkLogMacros.h:24
const void * GetData() const
Gives const access to the data.
The ImageTypeIsNotSupportedByGPU class specialized exception class for unsupported image formats...
Definition: mitkOclImage.h:197
void GetOffset(float *) const
Returns the image offset (needed for WorldToIndex Transform.
void * GetService(const ServiceReferenceBase &reference)
void SetDimensions(unsigned int *Dims)
Set the image dimensions through an unsigned int array.
int GetDimension() const
returns the dimensionality of the image
Definition: mitkOclImage.h:109
OclImage()
Constructor.
void SetDimension(unsigned short dim)
Set the dimensionality of the image.
#define MITK_WARN
Definition: mitkLogMacros.h:23
float GetSpacing(int)
returns the spacing of the image for specified dimension
void InitializeMITKImage()
Initialize the internal variable of type mitk::Image.
virtual void * TransferDataToCPU(cl_command_queue)
Copies the in GMEM stored data to RAM.
bool IsModified(int _type)
Returns the status of the image buffer.
virtual int TransferDataToGPU(cl_command_queue)
Copies the RAM-stored data to GMEM.
static Pointer New()
#define mitkThrowException(classname)
void InitializeByMitkImage(mitk::Image::Pointer _image)
Initialze the OclImage with an mitkImage.
#define MAX_DIMS
Definition: mitkOclImage.h:23
virtual cl_context GetContext() const =0
Returns a valid OpenCL Context (if applicable) or NULL if none present.
ImageReadAccessor class to get locked read access for a particular image part.
void Modified(int _type)
Set the modified flag for one of the buffers.
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
void oclPrintMemObjectInfo(cl_mem memobj)
Prints the available memory info about the given object to std::cout.
void SetPixelType(const cl_image_format *)
Set the pixel type for the image to be used.
Declaration of the OpenCL Resources micro-service.