23 #include <QTextStream> 
   32 QLatin1String QgsOpenClUtils::SETTINGS_GLOBAL_ENABLED_KEY = QLatin1String( 
"OpenClEnabled" );
 
   33 QLatin1String QgsOpenClUtils::SETTINGS_DEFAULT_DEVICE_KEY = QLatin1String( 
"OpenClDefaultDevice" );
 
   35 bool QgsOpenClUtils::sAvailable = 
false;
 
   42   std::vector<cl::Platform> platforms;
 
   43   cl::Platform::get( &platforms );
 
   44   std::vector<cl::Device> existingDevices;
 
   45   for ( 
const auto &p : platforms )
 
   47     const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
 
   49                                .arg( QString::fromStdString( platver ),
 
   50                                      QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
 
   51                                LOGMESSAGE_TAG, Qgis::MessageLevel::Info );
 
   52     if ( platver.find( 
"OpenCL " ) != std::string::npos )
 
   54       std::vector<cl::Device> _devices;
 
   58         p.getDevices( CL_DEVICE_TYPE_ALL, &_devices );
 
   60       catch ( cl::Error &e )
 
   63                                    .arg( errorText( e.err() ),
 
   64                                          QString::fromStdString( e.what() ),
 
   65                                          QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
 
   66                                    LOGMESSAGE_TAG, Qgis::MessageLevel::Warning );
 
   68       if ( _devices.size() > 0 )
 
   70         for ( 
unsigned long i = 0; i < _devices.size(); i++ )
 
   73                                      .arg( deviceId( _devices[i] ) ),
 
   74                                      LOGMESSAGE_TAG, Qgis::MessageLevel::Info );
 
   75           existingDevices.push_back( _devices[i] );
 
   80   return existingDevices;
 
   83 void QgsOpenClUtils::init()
 
   85   static std::once_flag initialized;
 
   86   std::call_once( initialized, [ = ]( )
 
   89     QLibrary openCLLib { QStringLiteral( 
"/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL" ) };
 
   91     QLibrary openCLLib { QStringLiteral( 
"OpenCL" ) };
 
   93     openCLLib.setLoadHints( QLibrary::LoadHint::ResolveAllSymbolsHint );
 
   94     if ( ! openCLLib.load() )
 
   97                                  .arg( openCLLib.errorString() ),
 
  103     HMODULE hModule = GetModuleHandle( 
"OpenCL.dll" );
 
  106       TCHAR pszFileName[1024];
 
  107       if ( GetModuleFileName( hModule, pszFileName, 1024 ) < 1024 )
 
  114         DWORD dwLen = GetFileVersionInfoSize( pszFileName, &dwUseless );
 
  117           LPTSTR lpVI = ( LPSTR ) malloc( dwLen );
 
  120             if ( GetFileVersionInfo( pszFileName, NULL, dwLen, lpVI ) )
 
  122               VS_FIXEDFILEINFO *lpFFI;
 
  123               if ( VerQueryValue( lpVI, 
"\\", ( LPVOID * ) &lpFFI, ( UINT * ) &dwUseless ) )
 
  126                                            .arg( lpFFI->dwProductVersionMS >> 16 )
 
  127                                            .arg( lpFFI->dwProductVersionMS & 0xffff )
 
  128                                            .arg( lpFFI->dwProductVersionLS >> 16 )
 
  129                                            .arg( lpFFI->dwProductVersionLS & 0xffff ),
 
  133               struct LANGANDCODEPAGE
 
  141               if ( VerQueryValue( lpVI, _T( 
"\\VarFileInfo\\Translation" ), ( LPVOID * ) &lpTranslate, ( UINT * ) &cbTranslate ) && cbTranslate >= 
sizeof( 
struct LANGANDCODEPAGE ) )
 
  143                 QStringList items = QStringList()
 
  144                                     << QStringLiteral( 
"Comments" )
 
  145                                     << QStringLiteral( 
"InternalName" )
 
  146                                     << QStringLiteral( 
"ProductName" )
 
  147                                     << QStringLiteral( 
"CompanyName" )
 
  148                                     << QStringLiteral( 
"LegalCopyright" )
 
  149                                     << QStringLiteral( 
"ProductVersion" )
 
  150                                     << QStringLiteral( 
"FileDescription" )
 
  151                                     << QStringLiteral( 
"LegalTrademarks" )
 
  152                                     << QStringLiteral( 
"PrivateBuild" )
 
  153                                     << QStringLiteral( 
"FileVersion" )
 
  154                                     << QStringLiteral( 
"OriginalFilename" )
 
  155                                     << QStringLiteral( 
"SpecialBuild" );
 
  156                 for ( 
auto d : items )
 
  159                   QString subBlock = QString( QStringLiteral( 
"\\StringFileInfo\\%1%2\\%3" ) )
 
  160                                      .arg( lpTranslate[0].wLanguage, 4, 16, QLatin1Char( 
'0' ) )
 
  161                                      .arg( lpTranslate[0].wCodePage, 4, 16, QLatin1Char( 
'0' ) )
 
  164                   QgsDebugMsg( QString( 
"d:%1 subBlock:%2" ).arg( d ).arg( subBlock ) );
 
  166                   BOOL r = VerQueryValue( lpVI, subBlock.toUtf8(), ( LPVOID * )&lpBuffer, ( UINT * )&dwUseless );
 
  168                   if ( r && lpBuffer && lpBuffer != INVALID_HANDLE_VALUE && dwUseless < 1023 )
 
  172                                                .arg( QString::fromLocal8Bit( lpBuffer ) ),
 
  198     catch ( cl::Error &e )
 
  201                                  .arg( 
errorText( e.err() ), QString::fromStdString( e.what() ) ),
 
  210   return *sSourcePath();
 
  215   *sSourcePath() = value;
 
  230         return QString::fromStdString( device.getInfo<CL_DEVICE_VENDOR>() );
 
  232         return QString::fromStdString( device.getInfo<CL_DEVICE_PROFILE>() );
 
  234         return QString::fromStdString( device.getInfo<CL_DEVICE_VERSION>() );
 
  235       case Info::ImageSupport:
 
  236         return device.getInfo<CL_DEVICE_IMAGE_SUPPORT>() ? QStringLiteral( 
"True" ) : QStringLiteral( 
"False" );
 
  237       case Info::Image2dMaxHeight:
 
  238         return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>() );
 
  239       case Info::MaxMemAllocSize:
 
  240         return QString::number( device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() );
 
  241       case Info::Image2dMaxWidth:
 
  242         return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() );
 
  245         const unsigned long type( device.getInfo<CL_DEVICE_TYPE>() );
 
  249           case CL_DEVICE_TYPE_CPU:
 
  250             mappedType = QgsOpenClUtils::HardwareType::CPU;
 
  252           case CL_DEVICE_TYPE_GPU:
 
  253             mappedType = QgsOpenClUtils::HardwareType::GPU;
 
  256             mappedType = QgsOpenClUtils::HardwareType::Other;
 
  258         const QMetaEnum metaEnum = QMetaEnum::fromType<QgsOpenClUtils::HardwareType>();
 
  259         return metaEnum.valueToKey( mappedType );
 
  262         return QString::fromStdString( device.getInfo<CL_DEVICE_NAME>() );
 
  265   catch ( cl::Error &e )
 
  268     QgsDebugMsgLevel( QStringLiteral( 
"Error %1 getting info for OpenCL device: %2" )
 
  269                       .arg( 
errorText( e.err() ), QString::fromStdString( e.what() ) ),
 
  279   return QgsSettings().
value( SETTINGS_GLOBAL_ENABLED_KEY, 
false, QgsSettings::Section::Core ).toBool();
 
  284   return cl::Device::getDefault();
 
  290   if ( cl::Platform::getDefault()() )
 
  292     const std::string platver = cl::Platform::getDefault().getInfo<CL_PLATFORM_VERSION>();
 
  293     if ( platver.find( 
"OpenCL " ) != std::string::npos )
 
  295       version = QString::fromStdString( platver.substr( 7 ) ).split( 
' ' ).first();
 
  308   return QgsSettings().
value( SETTINGS_DEFAULT_DEVICE_KEY, QString( ), QgsSettings::Section::Core ).toString();
 
  313   return QStringLiteral( 
"%1|%2|%3|%4" )
 
  314          .arg( 
deviceInfo( QgsOpenClUtils::Info::Name, device ) )
 
  315          .arg( 
deviceInfo( QgsOpenClUtils::Info::Vendor, device ) )
 
  316          .arg( 
deviceInfo( QgsOpenClUtils::Info::Version, device ) )
 
  317          .arg( 
deviceInfo( QgsOpenClUtils::Info::Type, device ) );
 
  320 bool QgsOpenClUtils::activate( 
const QString &preferredDeviceId )
 
  329     std::vector<cl::Platform> platforms;
 
  330     cl::Platform::get( &platforms );
 
  333     bool deviceFound = 
false;
 
  334     for ( 
const auto &p : platforms )
 
  338       const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
 
  339       QgsDebugMsg( QStringLiteral( 
"Found OpenCL platform %1: %2" ).arg( QString::fromStdString( platver ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
 
  340       if ( platver.find( 
"OpenCL " ) != std::string::npos )
 
  342         std::vector<cl::Device> 
devices;
 
  346           p.getDevices( CL_DEVICE_TYPE_ALL, &
devices );
 
  348           if ( ! preferredDeviceId.isEmpty() )
 
  350             for ( 
const auto &_dev : 
devices )
 
  352               if ( preferredDeviceId == 
deviceId( _dev ) )
 
  365             for ( 
const auto &_dev : 
devices )
 
  367               if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
 
  380             for ( 
const auto &_dev : 
devices )
 
  382               if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU )
 
  397         catch ( cl::Error &e )
 
  399           QgsDebugMsg( QStringLiteral( 
"Error %1 on platform %3 searching for OpenCL device: %2" )
 
  401                              QString::fromStdString( e.what() ),
 
  402                              QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
 
  414       const cl::Platform newP = cl::Platform::setDefault( plat );
 
  423         cl::Device::setDefault( dev );
 
  425                                    .arg( QString::fromStdString( dev.getInfo<CL_DEVICE_NAME>() ) ),
 
  432   catch ( cl::Error &e )
 
  435                                .arg( 
errorText( e.err() ), QString::fromStdString( e.what() ) ),
 
  444   return QStringLiteral(
 
  445            "Type: <b>%9</b><br>" 
  446            "Name: <b>%1</b><br>" 
  447            "Vendor: <b>%2</b><br>" 
  448            "Profile: <b>%3</b><br>" 
  449            "Version: <b>%4</b><br>" 
  450            "Image support: <b>%5</b><br>" 
  451            "Max image2d width: <b>%6</b><br>" 
  452            "Max image2d height: <b>%7</b><br>" 
  453            "Max mem alloc size: <b>%8</b><br>" 
  467   for ( 
const auto &dev : 
devices( ) )
 
  494   if ( file.open( QFile::ReadOnly | QFile::Text ) )
 
  496     QTextStream in( &file );
 
  497     source_str = in.readAll();
 
  509   const QString path = QStringLiteral( 
"%1/%2.cl" ).arg( 
sourcePath(), baseName );
 
  515   cl::BuildLogType build_logs = error.getBuildLog();
 
  517   if ( build_logs.size() > 0 )
 
  518     build_log = QString::fromStdString( build_logs[0].second );
 
  526     case 0: 
return QStringLiteral( 
"CL_SUCCESS" );
 
  527     case -1: 
return QStringLiteral( 
"CL_DEVICE_NOT_FOUND" );
 
  528     case -2: 
return QStringLiteral( 
"CL_DEVICE_NOT_AVAILABLE" );
 
  529     case -3: 
return QStringLiteral( 
"CL_COMPILER_NOT_AVAILABLE" );
 
  530     case -4: 
return QStringLiteral( 
"CL_MEM_OBJECT_ALLOCATION_FAILURE" );
 
  531     case -5: 
return QStringLiteral( 
"CL_OUT_OF_RESOURCES" );
 
  532     case -6: 
return QStringLiteral( 
"CL_OUT_OF_HOST_MEMORY" );
 
  533     case -7: 
return QStringLiteral( 
"CL_PROFILING_INFO_NOT_AVAILABLE" );
 
  534     case -8: 
return QStringLiteral( 
"CL_MEM_COPY_OVERLAP" );
 
  535     case -9: 
return QStringLiteral( 
"CL_IMAGE_FORMAT_MISMATCH" );
 
  536     case -10: 
return QStringLiteral( 
"CL_IMAGE_FORMAT_NOT_SUPPORTED" );
 
  537     case -12: 
return QStringLiteral( 
"CL_MAP_FAILURE" );
 
  538     case -13: 
return QStringLiteral( 
"CL_MISALIGNED_SUB_BUFFER_OFFSET" );
 
  539     case -14: 
return QStringLiteral( 
"CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST" );
 
  540     case -15: 
return QStringLiteral( 
"CL_COMPILE_PROGRAM_FAILURE" );
 
  541     case -16: 
return QStringLiteral( 
"CL_LINKER_NOT_AVAILABLE" );
 
  542     case -17: 
return QStringLiteral( 
"CL_LINK_PROGRAM_FAILURE" );
 
  543     case -18: 
return QStringLiteral( 
"CL_DEVICE_PARTITION_FAILED" );
 
  544     case -19: 
return QStringLiteral( 
"CL_KERNEL_ARG_INFO_NOT_AVAILABLE" );
 
  545     case -30: 
return QStringLiteral( 
"CL_INVALID_VALUE" );
 
  546     case -31: 
return QStringLiteral( 
"CL_INVALID_DEVICE_TYPE" );
 
  547     case -32: 
return QStringLiteral( 
"CL_INVALID_PLATFORM" );
 
  548     case -33: 
return QStringLiteral( 
"CL_INVALID_DEVICE" );
 
  549     case -34: 
return QStringLiteral( 
"CL_INVALID_CONTEXT" );
 
  550     case -35: 
return QStringLiteral( 
"CL_INVALID_QUEUE_PROPERTIES" );
 
  551     case -36: 
return QStringLiteral( 
"CL_INVALID_COMMAND_QUEUE" );
 
  552     case -37: 
return QStringLiteral( 
"CL_INVALID_HOST_PTR" );
 
  553     case -38: 
return QStringLiteral( 
"CL_INVALID_MEM_OBJECT" );
 
  554     case -39: 
return QStringLiteral( 
"CL_INVALID_IMAGE_FORMAT_DESCRIPTOR" );
 
  555     case -40: 
return QStringLiteral( 
"CL_INVALID_IMAGE_SIZE" );
 
  556     case -41: 
return QStringLiteral( 
"CL_INVALID_SAMPLER" );
 
  557     case -42: 
return QStringLiteral( 
"CL_INVALID_BINARY" );
 
  558     case -43: 
return QStringLiteral( 
"CL_INVALID_BUILD_OPTIONS" );
 
  559     case -44: 
return QStringLiteral( 
"CL_INVALID_PROGRAM" );
 
  560     case -45: 
return QStringLiteral( 
"CL_INVALID_PROGRAM_EXECUTABLE" );
 
  561     case -46: 
return QStringLiteral( 
"CL_INVALID_KERNEL_NAME" );
 
  562     case -47: 
return QStringLiteral( 
"CL_INVALID_KERNEL_DEFINITION" );
 
  563     case -48: 
return QStringLiteral( 
"CL_INVALID_KERNEL" );
 
  564     case -49: 
return QStringLiteral( 
"CL_INVALID_ARG_INDEX" );
 
  565     case -50: 
return QStringLiteral( 
"CL_INVALID_ARG_VALUE" );
 
  566     case -51: 
return QStringLiteral( 
"CL_INVALID_ARG_SIZE" );
 
  567     case -52: 
return QStringLiteral( 
"CL_INVALID_KERNEL_ARGS" );
 
  568     case -53: 
return QStringLiteral( 
"CL_INVALID_WORK_DIMENSION" );
 
  569     case -54: 
return QStringLiteral( 
"CL_INVALID_WORK_GROUP_SIZE" );
 
  570     case -55: 
return QStringLiteral( 
"CL_INVALID_WORK_ITEM_SIZE" );
 
  571     case -56: 
return QStringLiteral( 
"CL_INVALID_GLOBAL_OFFSET" );
 
  572     case -57: 
return QStringLiteral( 
"CL_INVALID_EVENT_WAIT_LIST" );
 
  573     case -58: 
return QStringLiteral( 
"CL_INVALID_EVENT" );
 
  574     case -59: 
return QStringLiteral( 
"CL_INVALID_OPERATION" );
 
  575     case -60: 
return QStringLiteral( 
"CL_INVALID_GL_OBJECT" );
 
  576     case -61: 
return QStringLiteral( 
"CL_INVALID_BUFFER_SIZE" );
 
  577     case -62: 
return QStringLiteral( 
"CL_INVALID_MIP_LEVEL" );
 
  578     case -63: 
return QStringLiteral( 
"CL_INVALID_GLOBAL_WORK_SIZE" );
 
  579     case -64: 
return QStringLiteral( 
"CL_INVALID_PROPERTY" );
 
  580     case -65: 
return QStringLiteral( 
"CL_INVALID_IMAGE_DESCRIPTOR" );
 
  581     case -66: 
return QStringLiteral( 
"CL_INVALID_COMPILER_OPTIONS" );
 
  582     case -67: 
return QStringLiteral( 
"CL_INVALID_LINKER_OPTIONS" );
 
  583     case -68: 
return QStringLiteral( 
"CL_INVALID_DEVICE_PARTITION_COUNT" );
 
  584     case -69: 
return QStringLiteral( 
"CL_INVALID_PIPE_SIZE" );
 
  585     case -70: 
return QStringLiteral( 
"CL_INVALID_DEVICE_QUEUE" );
 
  586     case -71: 
return QStringLiteral( 
"CL_INVALID_SPEC_ID" );
 
  587     case -72: 
return QStringLiteral( 
"CL_MAX_SIZE_RESTRICTION_EXCEEDED" );
 
  588     case -1002: 
return QStringLiteral( 
"CL_INVALID_D3D10_DEVICE_KHR" );
 
  589     case -1003: 
return QStringLiteral( 
"CL_INVALID_D3D10_RESOURCE_KHR" );
 
  590     case -1004: 
return QStringLiteral( 
"CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR" );
 
  591     case -1005: 
return QStringLiteral( 
"CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR" );
 
  592     case -1006: 
return QStringLiteral( 
"CL_INVALID_D3D11_DEVICE_KHR" );
 
  593     case -1007: 
return QStringLiteral( 
"CL_INVALID_D3D11_RESOURCE_KHR" );
 
  594     case -1008: 
return QStringLiteral( 
"CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR" );
 
  595     case -1009: 
return QStringLiteral( 
"CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR" );
 
  596     case -1010: 
return QStringLiteral( 
"CL_INVALID_DX9_MEDIA_ADAPTER_KHR" );
 
  597     case -1011: 
return QStringLiteral( 
"CL_INVALID_DX9_MEDIA_SURFACE_KHR" );
 
  598     case -1012: 
return QStringLiteral( 
"CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR" );
 
  599     case -1013: 
return QStringLiteral( 
"CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR" );
 
  600     case -1093: 
return QStringLiteral( 
"CL_INVALID_EGL_OBJECT_KHR" );
 
  601     case -1092: 
return QStringLiteral( 
"CL_EGL_RESOURCE_NOT_ACQUIRED_KHR" );
 
  602     case -1001: 
return QStringLiteral( 
"CL_PLATFORM_NOT_FOUND_KHR" );
 
  603     case -1057: 
return QStringLiteral( 
"CL_DEVICE_PARTITION_FAILED_EXT" );
 
  604     case -1058: 
return QStringLiteral( 
"CL_INVALID_PARTITION_COUNT_EXT" );
 
  605     case -1059: 
return QStringLiteral( 
"CL_INVALID_PARTITION_NAME_EXT" );
 
  606     case -1094: 
return QStringLiteral( 
"CL_INVALID_ACCELERATOR_INTEL" );
 
  607     case -1095: 
return QStringLiteral( 
"CL_INVALID_ACCELERATOR_TYPE_INTEL" );
 
  608     case -1096: 
return QStringLiteral( 
"CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL" );
 
  609     case -1097: 
return QStringLiteral( 
"CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL" );
 
  610     case -1000: 
return QStringLiteral( 
"CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR" );
 
  611     case -1098: 
return QStringLiteral( 
"CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL" );
 
  612     case -1099: 
return QStringLiteral( 
"CL_INVALID_VA_API_MEDIA_SURFACE_INTEL" );
 
  613     case -1100: 
return QStringLiteral( 
"CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL" );
 
  614     case -1101: 
return QStringLiteral( 
"CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL" );
 
  615     default: 
return QStringLiteral( 
"CL_UNKNOWN_ERROR" );
 
  627     return cl::CommandQueue( 
context );
 
  632     const cl_command_queue_properties properties = 0;
 
  634     cl_command_queue queue = clCreateCommandQueue( 
context(), device(),  properties, 
nullptr );
 
  636     return cl::CommandQueue( queue, 
true );
 
  643   static std::once_flag contextCreated;
 
  644   std::call_once( contextCreated, [ = ]()
 
  646     if ( 
available() && cl::Platform::getDefault()() && cl::Device::getDefault()() )
 
  648       context = cl::Context( cl::Device::getDefault() );
 
  670     if ( ok && version < 2.0f )
 
  672       program.build( QStringLiteral( 
"-cl-std=CL%1 -I\"%2\"" )
 
  678       program.build( QStringLiteral( 
"-I\"%1\"" )
 
  682   catch ( cl::BuildError &e )
 
  685     if ( build_log.isEmpty() )
 
  686       build_log = QObject::tr( 
"Build logs not available!" );
 
  687     const QString err = QObject::tr( 
"Error building OpenCL program: %1" )
 
  690     if ( exceptionBehavior == 
Throw )
 
  693   catch ( cl::Error &e )
 
  695     const QString err = QObject::tr( 
"Error %1 building OpenCL program in %2" )
 
  696                         .arg( 
errorText( e.err() ), QString::fromStdString( e.what() ) );