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() ) );