diff --git a/Modules/OpenCL/files.cmake b/Modules/OpenCL/files.cmake index 799077854e..c1f158a404 100644 --- a/Modules/OpenCL/files.cmake +++ b/Modules/OpenCL/files.cmake @@ -1,23 +1,26 @@ set(CPP_FILES # helper classes mitkOclUtils.cpp mitkOclResourceServiceImpl_Private.cpp mitkOclImageFormats.cpp # module activator mitkOpenCLActivator.cpp # base data and filter objects mitkOclBaseData.cpp mitkOclImage.cpp + mitkOclDataSet.cpp mitkOclFilter.cpp mitkOclImageFilter.cpp + mitkOclDataSetFilter.cpp mitkOclImageToImageFilter.cpp + mitkOclDataSetToDataSetFilter.cpp # own filter implementations mitkOclBinaryThresholdImageFilter.cpp ) set(RESOURCE_FILES BinaryThresholdFilter.cl ) diff --git a/Modules/OpenCL/mitkOclDataSet.cpp b/Modules/OpenCL/mitkOclDataSet.cpp new file mode 100644 index 0000000000..0c58eec02d --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSet.cpp @@ -0,0 +1,155 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkOclDataSet.h" +#include "mitkCommon.h" +#include "mitkLogMacros.h" + +#include "mitkOclUtils.h" + +#include + +mitk::OclDataSet::OclDataSet() : m_gpuBuffer(nullptr), m_context(nullptr), m_bufferSize(0), m_gpuModified(false), m_cpuModified(false), + m_Data(nullptr), m_size(0), m_BpE(1) +{ +} + +mitk::OclDataSet::~OclDataSet() +{ + MITK_INFO << "OclDataSet Destructor"; + + //release GMEM Image buffer + if (m_gpuBuffer) clReleaseMemObject(m_gpuBuffer); +} + + +cl_mem mitk::OclDataSet::CreateGPUBuffer(unsigned int _size, unsigned int _bpe) +{ + MITK_INFO << "InitializeGPUBuffer call with: BPE=" << _bpe; + + m_bufferSize = _size; + + m_BpE = _bpe; + + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + m_context = resources->GetContext(); + + int clErr; + m_gpuBuffer = clCreateBuffer(m_context, CL_MEM_READ_ONLY, m_bufferSize * m_BpE, nullptr, &clErr); + + CHECK_OCL_ERR(clErr); + + return m_gpuBuffer; +} + +bool mitk::OclDataSet::IsModified(int _type) +{ + if (_type) return m_cpuModified; + else return m_gpuModified; +} + +void mitk::OclDataSet::Modified(int _type) +{ + // defines... GPU: 0, CPU: 1 + m_cpuModified = _type; + m_gpuModified = !_type; +} + +int mitk::OclDataSet::TransferDataToGPU(cl_command_queue gpuComQueue) +{ + cl_int clErr = 0; + + // check whether an image present + if (m_Data == nullptr){ + MITK_ERROR("ocl.DataSet") << "(mitk) No data present!\n"; + return -1; + } + + // there is a need for copy only if RAM-Data newer then GMEM data + if (m_cpuModified) + { + //check the buffer + if(m_gpuBuffer == nullptr) + { + MITK_ERROR("ocl.DataSet") << "(mitk) No GPU buffer present!\n"; + return -1; + } + + if (m_gpuBuffer != nullptr) + { + clErr = clEnqueueWriteBuffer(gpuComQueue, m_gpuBuffer, CL_TRUE, 0, m_bufferSize * m_BpE, m_Data, 0, NULL, NULL); + } + else + { + MITK_ERROR << "No GPU buffer present!"; + } + CHECK_OCL_ERR(clErr); + m_gpuModified = true; + } + + return clErr; +} + +cl_mem mitk::OclDataSet::GetGPUBuffer() +{ + // clGetMemObjectInfo() + cl_mem_object_type memInfo; + cl_int clErr = 0; + + // query image object info only if already initialized + if( this->m_gpuBuffer ) + { + clErr = clGetMemObjectInfo(this->m_gpuBuffer, CL_MEM_TYPE, sizeof(cl_mem_object_type), &memInfo, nullptr ); + CHECK_OCL_ERR(clErr); + } + + MITK_INFO << "Querying info for object, recieving: " << memInfo; + + return m_gpuBuffer; +} + +void* mitk::OclDataSet::TransferDataToCPU(cl_command_queue gpuComQueue) +{ + cl_int clErr = 0; + + // if image created on GPU, needs to create mitk::Image + if( m_gpuBuffer == nullptr ){ + MITK_ERROR("ocl.DataSet") << "(mitk) No buffer present!\n"; + return nullptr; + } + + // check buffersize + char* data = new char[m_bufferSize * m_BpE]; + + // debug info + oclPrintMemObjectInfo( m_gpuBuffer ); + + clErr = clEnqueueReadBuffer( gpuComQueue, m_gpuBuffer, CL_FALSE, 0, m_bufferSize * m_BpE, data ,0, nullptr, nullptr); + CHECK_OCL_ERR(clErr); + + clFlush( gpuComQueue ); + // the cpu data is same as gpu + this->m_gpuModified = false; + + return (void*) data; +} + +void mitk::OclDataSet::SetSize(unsigned short size) +{ + m_size = size; +} \ No newline at end of file diff --git a/Modules/OpenCL/mitkOclDataSet.h b/Modules/OpenCL/mitkOclDataSet.h new file mode 100644 index 0000000000..93926ace86 --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSet.h @@ -0,0 +1,133 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __mitkOclDataSet_h +#define __mitkOclDataSet_h + +#define GPU_DATA 0 +#define CPU_DATA 1 + +#include +#include "MitkOpenCLExports.h" + +#include "mitkOclBaseData.h" +#include "mitkOpenCLActivator.h" + +#include + +namespace mitk { + +/*! + * \brief Class implementing processing of arbitrary data sets for GPU Image Processing + * + * The class holds a pointer to the data stored in RAM and performs an + * on-demand-copy to the graphics memory. It is the basic data structure for all + * mitk::oclDataSetToDataSetFilter classes + */ +class MITKOPENCL_EXPORT OclDataSet : public OclBaseData +{ +public: + mitkClassMacro(OclDataSet, OclBaseData); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /*! \brief Copies the RAM-stored data to GMEM */ + virtual int TransferDataToGPU(cl_command_queue); + + /*! \brief Copies the in GMEM stored data to RAM */ + virtual void* TransferDataToCPU(cl_command_queue); + + /*! \brief Returns the pointer to the referenced data */ + void* GetData() + { + return m_Data; + } + + /** Returns the pointer to the GPU buffer */ + cl_mem GetGPUBuffer(); + + /** Create the GPU buffer for image + * + */ + cl_mem CreateGPUBuffer(unsigned int _size, unsigned int _bpe); + + /** \brief Returns the status of the image buffer + * + * @param _type The flag to specify the buffer type ( GPU / CPU ) + */ + bool IsModified(int _type); + + using OclBaseData::Modified; + + /** \brief Set the modified flag for one of the buffers + * + * @param _type The flag to specify the buffer type ( GPU / CPU ) + */ + void Modified(int _type); + + /** \brief Initialze the OclDataSet with data. */ + void SetData(void* data) + { + this->m_cpuModified = true; + this->m_gpuModified = false; + m_Data = data; + } + + /*! \brief returns the size of the DataSet */ + int GetSize() const + { + return this->m_size; + } + + short GetBytesPerElement() const + { + return this->m_BpE; + } + + /** @brief Set the DataSet size*/ + void SetSize(unsigned short size); + +protected: + /*! \brief Constructor */ + OclDataSet(); + + /** @brief Destructor */ + virtual ~OclDataSet(); + + /*! GMEM Image buffer */ + cl_mem m_gpuBuffer; + + /*! GPU Context the Buffer was created in, needed for access */ + cl_context m_context; + + /*! GMEM Buffer Size */ + unsigned int m_bufferSize; + +private: + + bool m_gpuModified; + bool m_cpuModified; + + /*! Reference to the data */ + void* m_Data; + + unsigned short m_size; + + unsigned short m_BpE; +}; + +} +#endif //__mitkOclDataSet_h diff --git a/Modules/OpenCL/mitkOclDataSetFilter.cpp b/Modules/OpenCL/mitkOclDataSetFilter.cpp new file mode 100644 index 0000000000..83112f42ae --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSetFilter.cpp @@ -0,0 +1,41 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkOclDataSetFilter.h" +#include "mitkOclFilter.h" +#include "mitkOclDataSet.h" + +mitk::OclDataSetFilter::OclDataSetFilter() +{ +} + +mitk::OclDataSetFilter::~OclDataSetFilter() +{ +} + +void mitk::OclDataSetFilter::SetInput(mitk::OclDataSet::Pointer DataSet) +{ + m_Input = DataSet; +} + +void mitk::OclDataSetFilter::SetInput(void* DataSet, unsigned int size, unsigned int BpE) +{ + m_Input = mitk::OclDataSet::New(); + m_Input->SetData(DataSet); + m_Input->CreateGPUBuffer(size, BpE); + m_CurrentSize = size; +} + diff --git a/Modules/OpenCL/mitkOclDataSetFilter.h b/Modules/OpenCL/mitkOclDataSetFilter.h new file mode 100644 index 0000000000..1f09669a78 --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSetFilter.h @@ -0,0 +1,63 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __mitkOclDataSetFilter_h +#define __mitkOclDataSetFilter_h + +#include "mitkOclFilter.h" +#include "mitkOclDataSet.h" + +#define FILTER_UCHAR 0 +#define FILTER_SHORT 1 + +namespace mitk +{ +class OclFilter; +class OclDataSetFilter; + + /** + * \brief The OclDataSetFilter is the topmost class for all filter which take DataSets as input. + * + * The input DataSet can be intialized via an oclDataSet or a pointer to the data + * This makes it possible to create a filter pipeline of GPU-based filters + * and to bind this part into the CPU (ITK) filter pipeline. + */ +class MITKOPENCL_EXPORT OclDataSetFilter: public OclFilter +{ +public: + /** + * @brief SetInput SetInput Set the input DataSet (as mitk::OclDataSet). + * @param DataSet The DataSet in mitk::OclDataSet. + */ + void SetInput(mitk::OclDataSet::Pointer DataSet); + + /** + * @brief SetInput Set the input DataSet (as mitk::DataSet). + * @param DataSet The DataSet in mitk::DataSet. + */ + void SetInput(void* DataSet, unsigned int size, unsigned int BpE); + +protected: + OclDataSetFilter(); + + virtual ~OclDataSetFilter(); + + /** The input DataSet */ + mitk::OclDataSet::Pointer m_Input; + unsigned int m_CurrentSize; +}; +} +#endif // __mitkOclDataSetFilter_h diff --git a/Modules/OpenCL/mitkOclDataSetToDataSetFilter.cpp b/Modules/OpenCL/mitkOclDataSetToDataSetFilter.cpp new file mode 100644 index 0000000000..bbf4faf052 --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSetToDataSetFilter.cpp @@ -0,0 +1,93 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkOclDataSetToDataSetFilter.h" +#include "mitkOclDataSet.h" + +#include "mitkException.h" + +mitk::OclDataSetToDataSetFilter::OclDataSetToDataSetFilter() +{ + m_Output = mitk::OclDataSet::New(); +} + + +mitk::OclDataSetToDataSetFilter::~OclDataSetToDataSetFilter() +{ +} + +mitk::OclDataSet::Pointer mitk::OclDataSetToDataSetFilter::GetGPUOutput() +{ + return this->m_Output; +} + +void* mitk::OclDataSetToDataSetFilter::GetOutput() +{ + void* pData = m_Output->TransferDataToCPU(m_CommandQue); + return pData; +} + +int mitk::OclDataSetToDataSetFilter::GetBytesPerElem() +{ + return this->m_CurrentSizeOutput; +} + +bool mitk::OclDataSetToDataSetFilter::InitExec(cl_kernel ckKernel, unsigned int* dimensions, unsigned int outputBpE) +{ + cl_int clErr = 0; + + if (m_Input.IsNull()) + mitkThrow() << "Input DataSet is null."; + + // get DataSet size once + const unsigned int uiDataSetWidth = dimensions[0]; + const unsigned int uiDataSetHeight = dimensions[1]; + const unsigned int uiDataSetDepth = dimensions[2]; + + // compute work sizes + this->SetWorkingSize(8, uiDataSetWidth, 8, uiDataSetHeight, 8, uiDataSetDepth); + + cl_mem clBuffIn = m_Input->GetGPUBuffer(); + cl_mem clBuffOut = m_Output->GetGPUBuffer(); + + if (!clBuffIn) + { + if (m_Input->TransferDataToGPU(m_CommandQue) != CL_SUCCESS) + { + mitkThrow() << "Could not create / initialize gpu DataSet."; + } + + clBuffIn = m_Input->GetGPUBuffer(); + } + + // output DataSet not initialized + if (!clBuffOut) + { + MITK_DEBUG << "Create GPU DataSet call " << uiDataSetWidth << "x" << uiDataSetHeight << "x" << uiDataSetDepth; + clBuffOut = m_Output->CreateGPUBuffer(uiDataSetWidth*uiDataSetHeight*uiDataSetDepth, outputBpE); + m_CurrentSizeOutput = outputBpE; + } + + clErr = 0; + clErr = clSetKernelArg(ckKernel, 0, sizeof(cl_mem), &clBuffIn); + clErr |= clSetKernelArg(ckKernel, 1, sizeof(cl_mem), &clBuffOut); + CHECK_OCL_ERR(clErr); + + if (clErr != CL_SUCCESS) + mitkThrow() << "OpenCL Part initialization failed with " << GetOclErrorAsString(clErr); + + return(clErr == CL_SUCCESS); +} \ No newline at end of file diff --git a/Modules/OpenCL/mitkOclDataSetToDataSetFilter.h b/Modules/OpenCL/mitkOclDataSetToDataSetFilter.h new file mode 100644 index 0000000000..3d92f43c3e --- /dev/null +++ b/Modules/OpenCL/mitkOclDataSetToDataSetFilter.h @@ -0,0 +1,79 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __mitkOclDataSetToDataSetFilter_h +#define __mitkOclDataSetToDataSetFilter_h + +#include "mitkOclDataSetFilter.h" + +namespace mitk +{ +class OclDataSetFilter; +class OclDataSetToDataSetFilter; + +/** @class OclDataSetToDataSetFilter + * @brief The OclDataSetToDataSetFilter is the base class for all OpenCL DataSet filter generating DataSets. + */ +class MITKOPENCL_EXPORT OclDataSetToDataSetFilter: public OclDataSetFilter +{ +public: + /*! + * \brief Returns an pointer to the filtered data. + */ + void* GetOutput(); + + /*! + * \brief Returns a pointer to the graphics memory. + * + * Use this method when executing two and more filters on the GPU for fast access. + * This method does not copy the data to RAM. It returns only a pointer. + */ + mitk::OclDataSet::Pointer GetGPUOutput(); + +protected: + /** + * @brief OclDataSetToDataSetFilter Default constructor. + */ + OclDataSetToDataSetFilter(); + + /** @brief Destructor */ + virtual ~OclDataSetToDataSetFilter(); + + /** Output DataSet */ + mitk::OclDataSet::Pointer m_Output; + + /** @brief (Virtual) method Update() to be implemented in derived classes. */ + virtual void Update() = 0; + + /** + * @brief InitExec Initialize the execution + * @param ckKernel The GPU kernel. + * @throws mitk::Exception if something goes wrong. + * @return True for success. + */ + bool InitExec(cl_kernel ckKernel, unsigned int* dimensions, unsigned int outputBpE); + + /** @brief Get the memory size needed for each element */ + virtual int GetBytesPerElem(); + + unsigned int m_CurrentSizeOutput; + +private: + /** Block dimensions */ + unsigned int m_BlockDims[3]; +}; +} +#endif // __mitkOclDataSetToDataSetFilter_h