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