diff --git a/Modules/OpenCL/mitkOclResourceServiceImpl_Private.cpp b/Modules/OpenCL/mitkOclResourceServiceImpl_Private.cpp index c463a03f58..ff82ab83e5 100644 --- a/Modules/OpenCL/mitkOclResourceServiceImpl_Private.cpp +++ b/Modules/OpenCL/mitkOclResourceServiceImpl_Private.cpp @@ -1,259 +1,260 @@ /*=================================================================== 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 "mitkOclResourceServiceImpl_p.h" - OclResourceService::~OclResourceService() { } OclResourceServiceImpl::OclResourceServiceImpl() : m_ContextCollection(NULL), m_ProgramStorage() { + m_ProgramStorageMutex = itk::FastMutexLock::New(); } OclResourceServiceImpl::~OclResourceServiceImpl() { // if map non-empty, release all remaining if( m_ProgramStorage.size() ) { ProgramMapType::iterator it = m_ProgramStorage.begin(); while(it != m_ProgramStorage.end() ) { clReleaseProgram( it->second.program ); m_ProgramStorage.erase( it++ ); } } if( m_ContextCollection ) delete m_ContextCollection; } cl_context OclResourceServiceImpl::GetContext() const { if( m_ContextCollection == NULL ) { m_ContextCollection = new OclContextCollection(); } else if( !m_ContextCollection->CanProvideContext() ) { return NULL; } return m_ContextCollection->m_Context; } cl_command_queue OclResourceServiceImpl::GetCommandQueue() const { // check if queue valid cl_context clQueueContext; // check if there is a context available // if not create one if( ! m_ContextCollection ) { m_ContextCollection = new OclContextCollection(); } cl_int clErr = clGetCommandQueueInfo( m_ContextCollection->m_CommandQueue, CL_QUEUE_CONTEXT, sizeof(clQueueContext), &clQueueContext, NULL ); if( clErr != CL_SUCCESS || clQueueContext != m_ContextCollection->m_Context ) { MITK_WARN << "Have no valid command queue. Query returned : " << GetOclErrorAsString( clErr ); return NULL; } return m_ContextCollection->m_CommandQueue; } cl_device_id OclResourceServiceImpl::GetCurrentDevice() const { return m_ContextCollection->m_Devices[0]; } bool OclResourceServiceImpl::GetIsFormatSupported(cl_image_format *fmt) { cl_image_format temp; temp.image_channel_data_type = fmt->image_channel_data_type; temp.image_channel_order = fmt->image_channel_order; return (this->m_ContextCollection->m_ImageFormats->GetNearestSupported(&temp, fmt)); } void OclResourceServiceImpl::PrintContextInfo() const { // context and devices available if( m_ContextCollection->CanProvideContext() ) { oclPrintDeviceInfo( m_ContextCollection->m_Devices[0] ); } } void OclResourceServiceImpl::InsertProgram(cl_program _program_in, std::string name, bool forceOverride) { typedef std::pair < std::string, ProgramData > MapElemPair; std::pair< ProgramMapType::iterator, bool> retValue; ProgramData data; data.counter = 1; data.program = _program_in; + data.mutex = itk::FastMutexLock::New(); // program is not stored, insert first instance (count = 1) - m_ProgramStorageMutex.Lock(); + m_ProgramStorageMutex->Lock(); retValue = m_ProgramStorage.insert( MapElemPair(name, data) ); - m_ProgramStorageMutex.Unlock(); + m_ProgramStorageMutex->Unlock(); // insertion failed, i.e. a program with same name exists if( !retValue.second ) { std::string overrideMsg(""); if( forceOverride ) { // overwrite old instance m_ProgramStorage[name].program = _program_in; overrideMsg +=" The old program was overwritten!"; } MITK_WARN("OpenCL.ResourceService") << "The program " << name << " already exists." << overrideMsg; } } cl_program OclResourceServiceImpl::GetProgram(const std::string &name) { ProgramMapType::iterator it = m_ProgramStorage.find(name); if( it != m_ProgramStorage.end() ) { - it->second.mutex.Lock(); + it->second.mutex->Lock(); // first check if the program was deleted // while waiting on the mutex if ( it->second.counter == 0 ) mitkThrow() << "Requested OpenCL Program (" << name <<") not found." << "(deleted while waiting on the mutex)"; // increase the reference counter // by one if the program is requestet it->second.counter += 1; - it->second.mutex.Unlock(); + it->second.mutex->Unlock(); // return the cl_program return it->second.program; } mitkThrow() << "Requested OpenCL Program (" << name <<") not found."; } void OclResourceServiceImpl::InvalidateStorage() { // do nothing if no context present, there is also no storage if( !m_ContextCollection->CanProvideContext() ) return; // query the map ProgramMapType::iterator it = m_ProgramStorage.begin(); while(it != m_ProgramStorage.end() ) { // query the program build status cl_build_status status; unsigned int query = clGetProgramBuildInfo( it->second.program, m_ContextCollection->m_Devices[0], CL_PROGRAM_BUILD_STATUS, sizeof(cl_int), &status, NULL ); CHECK_OCL_ERR( query ) MITK_DEBUG << "Quering status for " << it->first << std::endl; // remove program if no succesfull build // we need to pay attention to the increment of the iterator when erasing current element if( status != CL_BUILD_SUCCESS ) { MITK_DEBUG << " +-- Build failed " << std::endl; m_ProgramStorage.erase( it++ ); } else { ++it; } } } void OclResourceServiceImpl::RemoveProgram(const std::string& name) { ProgramMapType::iterator it = m_ProgramStorage.find(name); cl_int status = 0; cl_program program = NULL; if( it != m_ProgramStorage.end() ) { - it->second.mutex.Lock(); + it->second.mutex->Lock(); // decrease reference by one it->second.counter -= 1; - it->second.mutex.Unlock(); + it->second.mutex->Unlock(); // remove from the storage if( it->second.counter == 0 ) { program = it->second.program; - m_ProgramStorageMutex.Lock(); + m_ProgramStorageMutex->Lock(); m_ProgramStorage.erase(it); - m_ProgramStorageMutex.Unlock(); + m_ProgramStorageMutex->Unlock(); } // delete the program if( program ) { status = clReleaseProgram(program); CHECK_OCL_ERR( status ); } } else { MITK_WARN("OpenCL.ResourceService") << "Program name [" <CanProvideContext() ) return 0; unsigned int retValue = 0; switch(dimension) { case 0: if ( _imagetype == CL_MEM_OBJECT_IMAGE2D) clGetDeviceInfo( m_ContextCollection->m_Devices[0], CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof( cl_uint ), &retValue, NULL ); else clGetDeviceInfo( m_ContextCollection->m_Devices[0], CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof( cl_uint ), &retValue, NULL ); break; case 1: if ( _imagetype == CL_MEM_OBJECT_IMAGE2D) clGetDeviceInfo( m_ContextCollection->m_Devices[0], CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof( cl_uint ), &retValue, NULL ); else clGetDeviceInfo( m_ContextCollection->m_Devices[0], CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof( cl_uint ), &retValue, NULL ); break; case 2: if ( _imagetype == CL_MEM_OBJECT_IMAGE3D) clGetDeviceInfo( m_ContextCollection->m_Devices[0], CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof( cl_uint ), &retValue, NULL); break; default: MITK_WARN << "Could not recieve info. Desired dimension or object type does not exist. "; break; } return retValue; } diff --git a/Modules/OpenCL/mitkOclResourceServiceImpl_p.h b/Modules/OpenCL/mitkOclResourceServiceImpl_p.h index 915885ad57..72015fcf2f 100644 --- a/Modules/OpenCL/mitkOclResourceServiceImpl_p.h +++ b/Modules/OpenCL/mitkOclResourceServiceImpl_p.h @@ -1,182 +1,184 @@ /*=================================================================== 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 __mitkOclResourceServiceImpl_h #define __mitkOclResourceServiceImpl_h #include //Micro Services #include #include #include #include //ocl #include "mitkOclResourceService.h" #include "mitkOclUtils.h" #include "mitkOclImageFormats.h" +#include + //todo add docu! /** @struct OclContextCollection * @brief An capsulation of all OpenCL context related variables needed for the OclResourceService implementation * * The struct gets created on first call to GetContext in the OclResourceService and attepts to initialize all * relevant parts, i.e. the context itself, the device and the command queue */ struct OclContextCollection{ public: OclContextCollection() : m_Context(NULL), m_Devices(NULL), m_CreateContextFailed(false) { cl_int clErr = 0; size_t szParmDataBytes; cl_platform_id cpPlatform; cl_device_id m_cdDevice; try{ clErr = oclGetPlatformID( &cpPlatform); CHECK_OCL_ERR( clErr ); clErr = clGetDeviceIDs( cpPlatform, CL_DEVICE_TYPE_GPU, 1, &m_cdDevice, NULL); CHECK_OCL_ERR( clErr ); this->m_Context = clCreateContext( 0, 1, &m_cdDevice, NULL, NULL, &clErr); m_CreateContextFailed = (clErr != CL_SUCCESS); // get the info size clErr = clGetContextInfo(m_Context, CL_CONTEXT_DEVICES, 0,NULL, &szParmDataBytes ); this->m_Devices = (cl_device_id*) malloc(szParmDataBytes); // get device info clErr = clGetContextInfo(m_Context, CL_CONTEXT_DEVICES, szParmDataBytes, m_Devices, NULL); CHECK_OCL_ERR( clErr ); // create command queue m_CommandQueue = clCreateCommandQueue(m_Context, m_Devices[0], 0, &clErr); CHECK_OCL_ERR( clErr ); this->PrintContextInfo( ); // collect available image formats for current context this->m_ImageFormats = mitk::OclImageFormats::New(); this->m_ImageFormats->SetGPUContext(m_Context); } catch( std::exception& e) { MITK_ERROR("OpenCL.ResourceService") << "Exception while creating context: \n" << e.what(); } } ~OclContextCollection() { // if devices were allocated, delete if(m_Devices) { // TODO: Available first in OpenCL 1.2 : query the device for CL_PLATFORM_VERSION // through clGetPlatformInfo // clReleaseDevice(m_Devices[0]); delete [] m_Devices; } // if context was created release it if( m_Context ) clReleaseContext( this->m_Context ); } bool CanProvideContext() const { return ( m_Context != NULL && !m_CreateContextFailed ); } void PrintContextInfo() const { if( m_Devices ) { oclPrintDeviceInfo( m_Devices[0] ); } } /** The context */ cl_context m_Context; /** Available OpenCL devices */ cl_device_id* m_Devices; /** Class for handling (un)supported GPU image formats **/ mitk::OclImageFormats::Pointer m_ImageFormats; /** The command queue*/ cl_command_queue m_CommandQueue; bool m_CreateContextFailed; }; class OclResourceServiceImpl : public US_BASECLASS_NAME, public OclResourceService { private: // define programmdata private class struct ProgramData { int counter; cl_program program; - itk::SimpleFastMutexLock mutex; + itk::FastMutexLock::Pointer mutex; ProgramData() :counter(1), program(NULL) {} }; typedef std::map< std::string, ProgramData > ProgramMapType; //typedef std::map< std::string, std::pair< int, cl_program> > ProgramMapType; mutable OclContextCollection* m_ContextCollection; /** Map containing all available (allready compiled) OpenCL Programs */ ProgramMapType m_ProgramStorage; /** mutex for manipulating the program storage */ - itk::SimpleFastMutexLock m_ProgramStorageMutex; + itk::FastMutexLock::Pointer m_ProgramStorageMutex; public: OclResourceServiceImpl(); ~OclResourceServiceImpl(); cl_context GetContext() const; cl_command_queue GetCommandQueue() const; cl_device_id GetCurrentDevice() const; bool GetIsFormatSupported(cl_image_format *); void PrintContextInfo() const; void InsertProgram(cl_program _program_in, std::string name, bool forceOverride=true); cl_program GetProgram(const std::string&name); void InvalidateStorage(); void RemoveProgram(const std::string&name); unsigned int GetMaximumImageSize(unsigned int dimension, cl_mem_object_type _imagetype); }; #endif // __mitkOclResourceServiceImpl_h