CustusX  16.5.0-rc9
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxGPUImageBuffer.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 
34 #include "cxGPUImageBuffer.h"
35 
36 #include <QString>
37 
38 #include <vector>
39 #include <vtkImageData.h>
40 #include <vtkPointData.h>
41 #include <vtkUnsignedCharArray.h>
42 #include <vtkUnsignedShortArray.h>
43 #include <boost/cstdint.hpp>
44 #include "cxGLHelpers.h"
45 #include "cxLogger.h"
46 
47 
48 #ifndef WIN32
49 #define GL_GLEXT_PROTOTYPES
50 //#include <vtkgl.h>
51 
52 #ifdef __APPLE__
53 #include <OpenGL/glu.h>
54 #else
55 #include <GL/glu.h>
56 #endif
57 
58 #ifdef WIN32
59 #include <windows.h>
60 #include <GL/glext.h>
61 #endif
62 
63 
64 namespace cx
65 {
66 
70 {
71 public:
72  GLuint textureId;
74  bool mAllocated;
75  uint64_t mMTime;
77 
79  {
80  mAllocated = false;
81  mMTime = 0;
82  textureId = 0;
83  mMemorySize = 0;
84  }
86  {
87  release();
88  }
89 
90  virtual int getMemorySize()
91  {
92  return mMemorySize;
93  }
94 
95  virtual void SetImage (vtkImageDataPtr texture)
96  {
97  if (!texture)
98  {
99  std::cout << "error: bad buffer initialization: null image" << std::endl;
100  }
101  mTexture = texture;
102  }
103  virtual unsigned int getTextureUid() const
104  {
105  return textureId;
106  }
107 
113  virtual void allocate()
114  {
115  if (mAllocated) // do this only once.
116  {
117  return;
118  }
119  if (!mTexture)
120  {
121  std::cout << "error: bad volume buffer initialization" << std::endl;
122  return;
123  }
124 
125  glActiveTexture(GL_TEXTURE7);
126 
127  glEnable(GL_TEXTURE_3D);
128  glGenTextures(1, &textureId);
129  glDisable(GL_TEXTURE_3D);
130 
131  updateTexture();
132  mAllocated = true;
133  }
134  virtual void updateTexture()
135  {
136  if (mMTime == mTexture->GetMTime())
137  {
138  return;
139  }
140  mMTime = mTexture->GetMTime();
141  //vtkgl::ActiveTexture(getGLTextureForVolume(textureUnitIndex)); //TODO is this OK?
142  GLenum size,internalType;
143  boost::uint32_t dimx = mTexture ->GetDimensions( )[0];
144  boost::uint32_t dimy = mTexture ->GetDimensions( )[1];
145  boost::uint32_t dimz = mTexture ->GetDimensions( )[2];
146  mMemorySize = dimx * dimy * dimz;
147 
148  glEnable( GL_TEXTURE_3D );
149  glBindTexture(GL_TEXTURE_3D, textureId);
150  report_gl_error();
151  glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP );
152  glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP );
153  glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP );
154  glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
155  glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
156  switch (mTexture->GetScalarType())
157  {
158  case VTK_UNSIGNED_CHAR:
159  {
160  size = GL_UNSIGNED_BYTE;
161  internalType = GL_LUMINANCE;
162  }
163  break; //8UI_EXT; break;
164  case VTK_UNSIGNED_SHORT:
165  {
166  size = GL_UNSIGNED_SHORT;
167  internalType = GL_LUMINANCE16;
168  mMemorySize *= 2;
169  }
170  break; //16UI_EXT; break;
171  default:
172  size = 0;
173  internalType = 0;
174  std::cout << "Bit size not supported!" << std::endl;
175  QString dataType(mTexture->GetScalarTypeAsString());
176  CX_LOG_ERROR() << QString("Attempt to update 3D GL texture from type %1 failed. Only unsigned types supported").arg(dataType);
177  break;
178  }
179 
180  if (mTexture->GetNumberOfScalarComponents()==1)
181  {
182  void* data = mTexture->GetPointData()->GetScalars()->GetVoidPointer(0);
183  glTexImage3D(GL_TEXTURE_3D, 0, internalType, dimx, dimy, dimz, 0, GL_LUMINANCE, size, data);
184  }
185  else if (mTexture->GetNumberOfScalarComponents()==3)
186  {
187  internalType = GL_RGB;
188  void* data = mTexture->GetPointData()->GetScalars()->GetVoidPointer(0);
189  glTexImage3D(GL_TEXTURE_3D, 0, internalType, dimx, dimy, dimz, 0, GL_RGB, size, data);
190  mMemorySize *= 3;
191  }
192  else
193  {
194  std::cout << "unsupported number of image components" << std::endl;
195  }
196 
197  glDisable(GL_TEXTURE_3D);
198 
199  report_gl_error();
200  }
201 
206  virtual void bind(int textureUnitIndex)
207  {
208  this->updateTexture();
209  if (!mAllocated)
210  {
211  std::cout << "error: called bind() on unallocated volume buffer" << std::endl;
212  return;
213  }
214  glActiveTexture(getGLTextureForVolume(textureUnitIndex));
215  glBindTexture(GL_TEXTURE_3D, textureId);
216  report_gl_error();
217  }
218 
219  virtual void release()
220  {
221  glDeleteTextures(1, &textureId);
222  }
223 
224  int getGLTextureForVolume(int textureUnitIndex)
225  {
226  switch (textureUnitIndex)
227  {
228  case 0: return GL_TEXTURE0;
229  case 1: return GL_TEXTURE2;
230  case 2: return GL_TEXTURE4;
231  case 3: return GL_TEXTURE6;
232  case 4: return GL_TEXTURE8;
233  default: return -1;
234  }
235  }
236 };
237 
238 
242 {
243 public:
244  GLuint lutBuffer;
245  GLuint textureId;
248  uint64_t mMTime;
249 
251  {
252  mAllocated = false;
253  textureId = 0;
254  mMTime = 0;
255 // mDebugEnableCrossplatform=false;
256  }
258  {
259  release();
260  }
261 
262  virtual int getMemorySize()
263  {
264  if (!mTable)
265  return 0;
266  return mTable->GetNumberOfTuples() * mTable->GetNumberOfComponents() * sizeof(float);
267  }
268 
269 
270  //intput lookuptable is raw imported table
272  {
273  mTable = table;
274  }
275 
281  virtual void allocate()
282  {
283  if (!mTable)
284  {
285  std::cout << "error: bad lut buffer initialization" << std::endl;
286  return;
287  }
288 
289  if (!mAllocated)
290  {
291  glActiveTexture(GL_TEXTURE6);
292  glGenTextures(1, &textureId);
293  mAllocated = true;
294  }
295  this->updateTexture();
296  }
297 
298  virtual void updateTexture()
299  {
300  if (mMTime == mTable->GetMTime())
301  {
302  return;
303  }
304  mMTime = mTable->GetMTime();
305 
306  glActiveTexture(GL_TEXTURE6);
307  this->sendDataToGL();
308  report_gl_error();
309  }
310 
312  {
313  std::vector<float> lut;
314  int lutSize = mTable->GetNumberOfTuples();
315  int lutDataSize = lutSize * mTable->GetNumberOfComponents();
316  lut.resize(lutDataSize);
317  unsigned char* ptr = mTable->GetPointer(0);
318 
319  for (int i = 0; i < lut.size(); ++i)
320  {
321  lut[i] = ((float) *ptr) / 255.0;
322  ++ptr;
323  }
324 
325  glBindTexture(GL_TEXTURE_1D, textureId);
326  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
327  glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
328  glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
329  report_gl_error();
330 
331  glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA,
332  lutSize, 0,
333  GL_RGBA, GL_FLOAT, &(*lut.begin()));
334  report_gl_error();
335  }
336 
337  virtual void bind(int textureUnitIndex)
338  {
339  this->updateTexture();
340  if (!mAllocated)
341  {
342  std::cout << "error: called bind() on unallocated lut buffer" << std::endl;
343  return;
344  }
345  glActiveTexture(getGLTextureForLut(textureUnitIndex));
346  this->bindDataToGL();
347  report_gl_error();
348  }
349 
351  {
352  glBindTexture(GL_TEXTURE_1D, textureId);
353  }
354 
355  int getLutSize() const
356  {
357  return mTable->GetNumberOfTuples();
358  }
359 
360  virtual void release()
361  {
362  if (!mAllocated)
363  return;
364 
365  glDeleteTextures(1, &textureId);
366  }
367 
368  int getGLTextureForLut(int textureUnitIndex)
369  {
370  switch (textureUnitIndex)
371  {
372  case 0: return GL_TEXTURE1;
373  case 1: return GL_TEXTURE3;
374  case 2: return GL_TEXTURE5;
375  case 3: return GL_TEXTURE7;
376  case 4: return GL_TEXTURE9;
377  default: return -1;
378  }
379  }
380 };
381 
383 {
384  std::auto_ptr<GPUImageDataBufferImpl> retval(new GPUImageDataBufferImpl);
385  retval->SetImage(volume);
386  return GPUImageDataBufferPtr(retval.release());
387 }
388 
390 {
391  std::auto_ptr<GPUImageLutBufferImpl> retval(new GPUImageLutBufferImpl);
392  retval->SetColorMap(lut);
393  return GPUImageLutBufferPtr(retval.release());
394 }
395 
396 template<class BUFFER, class DATA_PTR>
397 boost::shared_ptr<BUFFER> createGPUImageBuffer(DATA_PTR val);
398 
399 template<>
400 boost::shared_ptr<GPUImageDataBuffer> createGPUImageBuffer<GPUImageDataBuffer>(vtkImageDataPtr val);
401 template<>
402 boost::shared_ptr<GPUImageLutBuffer> createGPUImageBuffer<GPUImageLutBuffer>(vtkUnsignedCharArrayPtr val);
403 
404 template<>
406 {
407  return createGPUImageDataBuffer(val);
408 }
409 template<>
410 boost::shared_ptr<GPUImageLutBuffer> createGPUImageBuffer<GPUImageLutBuffer>(vtkUnsignedCharArrayPtr val)
411 {
412  return createGPUImageLutBuffer(val);
413 }
414 
415 
416 //---------------------------------------------------------
417 GPUImageBufferRepository* GPUImageBufferRepository::mInstance = NULL;
418 //---------------------------------------------------------
419 
420 template<class DATA_PTR, class BUFFER>
422 {
423 public:
424  typedef boost::shared_ptr<BUFFER> BufferPtr;
425  typedef boost::weak_ptr<BUFFER> BufferWeakPtr;
426 
427  struct BufferStore
428  {
429  BufferStore(DATA_PTR data, BufferPtr buffer) : mData(data), mBuffer(buffer) {}
430  DATA_PTR mData;
432  };
433 public:
434 
435  BufferQueue() : mMaxBuffers(7)
436  {
437 
438  }
439  void setMaxBuffers(unsigned val)
440  {
441  mMaxBuffers = val;
442  }
443  void setName(const QString& name)
444  {
445  mName = name;
446  }
447 
452  BufferPtr get(DATA_PTR data)
453  {
454  // clear out deleted data
455  for (typename BufferMap::iterator iter=mRemovedData.begin(); iter!=mRemovedData.end(); )
456  {
457  if (!iter->second.lock())
458  {
459  typename BufferMap::iterator temp = iter;
460  ++iter;
461  mRemovedData.erase(temp);
462  }
463  else
464  {
465  ++iter;
466  }
467  }
468 
469  // reclaim weak pointer to buffer if it exists.
470  if (mRemovedData.count(data))
471  {
472  BufferPtr object = mRemovedData[data].lock();
473  if (object)
474  {
475  mData.push_front(BufferStore(data, object));
476  mRemovedData.erase(data);
477  }
478  }
479 
480  // move current data to front of buffer (i.e. increase importance)
481  BufferPtr retval;
482  for (typename std::list<BufferStore>::iterator iter=mData.begin(); iter!=mData.end(); ++iter)
483  {
484  if (iter->mData==data)
485  {
486  retval = iter->mBuffer; // retrieve data
487  mData.push_front(*iter); // push on queue front (most recent)
488  mData.erase(iter); // erase from old position
489  break;
490  }
491  }
492 
493  // create buffer if nonexistent
494  if (!retval)
495  {
496  retval = createGPUImageBuffer<BUFFER>(data);
497  mData.push_front(BufferStore(data, retval));
498  }
499 
500  // reduce repository size if too large.
501  while (mData.size()>mMaxBuffers)
502  {
503  mRemovedData[mData.back().mData] = mData.back().mBuffer;
504  mData.pop_back();;
505  }
506 
507  return retval;
508  }
509  int getMemoryUsage(int *textures)
510  {
511  int mem = 0;
512  if (textures)
513  {
514  *textures = mData.size();
515  }
516  for (typename std::list<BufferStore>::iterator iter=mData.begin(); iter!=mData.end(); ++iter)
517  {
518  mem += iter->mBuffer->getMemorySize();
519  }
520  return mem;
521  }
522 private:
523  typedef std::map<DATA_PTR, BufferWeakPtr> BufferMap;
524  BufferMap mRemovedData; // those buffers that are removed but still might live outside of the repo.
525  std::list<BufferStore> mData; // newest elems in front
526  unsigned mMaxBuffers;
527  QString mName; // debug
528 };
529 
531 {
532 public:
534  {
535  mVolumeBuffer.setName("Volume");
536  mLutBuffer.setName("Lut");
537 
538  mVolumeBuffer.setMaxBuffers(12);
539  mLutBuffer.setMaxBuffers(15);
540  }
543 };
544 
545 GPUImageBufferRepository::GPUImageBufferRepository()
546 {
547  mInternal = new GPUImageBufferRepositoryInternal();
548 }
549 
550 GPUImageBufferRepository::~GPUImageBufferRepository()
551 {
552  tearDown();
553 }
554 
556 {
557  tearDown();
558  mInternal = new GPUImageBufferRepositoryInternal();
559 }
560 
562 {
563  if (!mInstance)
564  {
565  mInstance = new GPUImageBufferRepository();
566  }
567  return mInstance;
568 }
569 
571 {
572  if(mInstance)
573  {
574  delete mInstance;
575  }
576  mInstance = NULL;
577 
578 }
579 
580 void GPUImageBufferRepository::tearDown()
581 {
582  delete mInternal;
583  mInternal = NULL;
584 }
585 
587 {
588  return mInternal->mVolumeBuffer.getMemoryUsage(textures);
589 }
590 
592 {
593  return mInternal->mVolumeBuffer.get(volume);
594 }
595 
597 {
598  return mInternal->mLutBuffer.get(lut);
599 }
600 
601 }
602 
603 #else
604 
605 namespace cx
606 {
608 void GPUImageBufferRepository::tearDown() {;}
609 }//namespace cx
610 
611 #endif //WIN32
612 
613 namespace cx
614 {
615 
616 }
Helper class for sharing GPU memory over several Views (GL contexts).
boost::shared_ptr< BUFFER > createGPUImageBuffer(DATA_PTR val)
BufferQueue< vtkImageDataPtr, GPUImageDataBuffer > mVolumeBuffer
boost::shared_ptr< GPUImageDataBuffer > createGPUImageBuffer< GPUImageDataBuffer, vtkImageDataPtr >(vtkImageDataPtr val)
GPUImageDataBufferPtr createGPUImageDataBuffer(vtkImageDataPtr volume)
vtkUnsignedCharArrayPtr mTable
virtual void SetColorMap(vtkUnsignedCharArrayPtr table)
virtual unsigned int getTextureUid() const
void setName(const QString &name)
BufferQueue< vtkUnsignedCharArrayPtr, GPUImageLutBuffer > mLutBuffer
Repository for GPU buffers.
vtkSmartPointer< class vtkUnsignedCharArray > vtkUnsignedCharArrayPtr
boost::shared_ptr< GPUImageDataBuffer > createGPUImageBuffer< GPUImageDataBuffer >(vtkImageDataPtr val)
virtual void bind(int textureUnitIndex)
GPUImageLutBufferPtr getGPUImageLutBuffer(vtkUnsignedCharArrayPtr lut)
void setMaxBuffers(unsigned val)
virtual void SetImage(vtkImageDataPtr texture)
#define CX_LOG_ERROR
Definition: cxLogger.h:114
int getGLTextureForLut(int textureUnitIndex)
GPUImageLutBufferPtr createGPUImageLutBuffer(vtkUnsignedCharArrayPtr lut)
boost::shared_ptr< class GPUImageDataBuffer > GPUImageDataBufferPtr
boost::weak_ptr< BUFFER > BufferWeakPtr
boost::shared_ptr< class GPUImageLutBuffer > GPUImageLutBufferPtr
int getGLTextureForVolume(int textureUnitIndex)
GPUImageDataBufferPtr getGPUImageDataBuffer(vtkImageDataPtr volume)
Helper class for sharing GPU memory over several Views (GL contexts).
static GPUImageBufferRepository * getInstance()
virtual void bind(int textureUnitIndex)
BufferStore(DATA_PTR data, BufferPtr buffer)
boost::shared_ptr< GPUImageLutBuffer > createGPUImageBuffer< GPUImageLutBuffer >(vtkUnsignedCharArrayPtr val)
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
boost::shared_ptr< BUFFER > BufferPtr
#define report_gl_error()
Definition: cxGLHelpers.h:50
int getMemoryUsage(int *textures)