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 (
auto &p : platforms )
47 std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
49 .arg( QString::fromStdString( platver ),
50 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
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>() ) ), LOGMESSAGE_TAG );
67 if ( _devices.size() > 0 )
69 for (
unsigned long i = 0; i < _devices.size(); i++ )
72 .arg( deviceId( _devices[i] ) ), LOGMESSAGE_TAG );
73 existingDevices.push_back( _devices[i] );
78 return existingDevices;
81 void QgsOpenClUtils::init()
83 static std::once_flag initialized;
84 std::call_once( initialized, [ = ]( )
86 QLibrary openCLLib{ QStringLiteral(
"OpenCL" ) };
87 openCLLib.setLoadHints( QLibrary::LoadHint::ResolveAllSymbolsHint );
88 if ( ! openCLLib.load() )
91 .arg( openCLLib.errorString() ),
97 HMODULE hModule = GetModuleHandle(
"OpenCL.dll" );
100 TCHAR pszFileName[1024];
101 if ( GetModuleFileName( hModule, pszFileName, 1024 ) < 1024 )
106 DWORD dwLen = GetFileVersionInfoSize( pszFileName, &dwUseless );
109 LPTSTR lpVI = ( LPSTR ) malloc( dwLen );
112 if ( GetFileVersionInfo( pszFileName, NULL, dwLen, lpVI ) )
114 VS_FIXEDFILEINFO *lpFFI;
115 if ( VerQueryValue( lpVI,
"\\", ( LPVOID * ) &lpFFI, ( UINT * ) &dwUseless ) )
118 .arg( lpFFI->dwProductVersionMS >> 16 )
119 .arg( lpFFI->dwProductVersionMS & 0xffff )
120 .arg( lpFFI->dwProductVersionLS >> 16 )
124 struct LANGANDCODEPAGE
132 if ( VerQueryValue( lpVI, _T(
"\\VarFileInfo\\Translation" ), ( LPVOID * ) &lpTranslate, ( UINT * ) &cbTranslate ) && cbTranslate >=
sizeof(
struct LANGANDCODEPAGE ) )
134 QStringList items = QStringList()
135 << QStringLiteral(
"Comments" )
136 << QStringLiteral(
"InternalName" )
137 << QStringLiteral(
"ProductName" )
138 << QStringLiteral(
"CompanyName" )
139 << QStringLiteral(
"LegalCopyright" )
140 << QStringLiteral(
"ProductVersion" )
141 << QStringLiteral(
"FileDescription" )
142 << QStringLiteral(
"LegalTrademarks" )
143 << QStringLiteral(
"PrivateBuild" )
144 << QStringLiteral(
"FileVersion" )
145 << QStringLiteral(
"OriginalFilename" )
146 << QStringLiteral(
"SpecialBuild" );
147 for (
auto d : items )
150 QString subBlock = QString( QStringLiteral(
"\\StringFileInfo\\%1%2\\%3" ) )
151 .arg( lpTranslate[0].wLanguage, 4, 16, QLatin1Char(
'0' ) )
152 .arg( lpTranslate[0].wCodePage, 4, 16, QLatin1Char(
'0' ) )
155 QgsDebugMsg( QString(
"d:%1 subBlock:%2" ).arg( d ).arg( subBlock ) );
157 BOOL r = VerQueryValue( lpVI, subBlock.toUtf8(), ( LPVOID * )&lpBuffer, ( UINT * )&dwUseless );
159 if ( r && lpBuffer && lpBuffer != INVALID_HANDLE_VALUE && dwUseless < 1023 )
186 catch ( cl::Error &e )
189 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
198 return *sSourcePath();
203 *sSourcePath() = value;
218 return QString::fromStdString( device.getInfo<CL_DEVICE_VENDOR>() );
220 return QString::fromStdString( device.getInfo<CL_DEVICE_PROFILE>() );
222 return QString::fromStdString( device.getInfo<CL_DEVICE_VERSION>() );
223 case Info::ImageSupport:
224 return device.getInfo<CL_DEVICE_IMAGE_SUPPORT>() ? QStringLiteral(
"True" ) : QStringLiteral(
"False" );
225 case Info::Image2dMaxHeight:
226 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>() );
227 case Info::MaxMemAllocSize:
228 return QString::number( device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() );
229 case Info::Image2dMaxWidth:
230 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() );
233 unsigned long type( device.getInfo<CL_DEVICE_TYPE>() );
237 case CL_DEVICE_TYPE_CPU:
238 mappedType = QgsOpenClUtils::HardwareType::CPU;
240 case CL_DEVICE_TYPE_GPU:
241 mappedType = QgsOpenClUtils::HardwareType::GPU;
244 mappedType = QgsOpenClUtils::HardwareType::Other;
246 QMetaEnum metaEnum = QMetaEnum::fromType<QgsOpenClUtils::HardwareType>();
247 return metaEnum.valueToKey( mappedType );
250 return QString::fromStdString( device.getInfo<CL_DEVICE_NAME>() );
253 catch ( cl::Error &e )
256 QgsDebugMsgLevel( QStringLiteral(
"Error %1 getting info for OpenCL device: %2" )
257 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
267 return QgsSettings().
value( SETTINGS_GLOBAL_ENABLED_KEY,
false, QgsSettings::Section::Core ).toBool();
272 return cl::Device::getDefault();
278 if ( cl::Platform::getDefault()() )
280 std::string platver = cl::Platform::getDefault().getInfo<CL_PLATFORM_VERSION>();
281 if ( platver.find(
"OpenCL " ) != std::string::npos )
283 version = QString::fromStdString( platver.substr( 7 ) ).split(
' ' ).first();
296 return QgsSettings().
value( SETTINGS_DEFAULT_DEVICE_KEY, QString( ), QgsSettings::Section::Core ).toString();
301 return QStringLiteral(
"%1|%2|%3|%4" )
302 .arg(
deviceInfo( QgsOpenClUtils::Info::Name, device ) )
303 .arg(
deviceInfo( QgsOpenClUtils::Info::Vendor, device ) )
304 .arg(
deviceInfo( QgsOpenClUtils::Info::Version, device ) )
305 .arg(
deviceInfo( QgsOpenClUtils::Info::Type, device ) );
308 bool QgsOpenClUtils::activate(
const QString &preferredDeviceId )
317 std::vector<cl::Platform> platforms;
318 cl::Platform::get( &platforms );
321 bool deviceFound =
false;
322 for (
auto &p : platforms )
326 std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
327 QgsDebugMsg( QStringLiteral(
"Found OpenCL platform %1: %2" ).arg( QString::fromStdString( platver ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
328 if ( platver.find(
"OpenCL " ) != std::string::npos )
330 std::vector<cl::Device>
devices;
334 p.getDevices( CL_DEVICE_TYPE_ALL, &
devices );
336 if ( ! preferredDeviceId.isEmpty() )
338 for (
const auto &_dev :
devices )
340 if ( preferredDeviceId ==
deviceId( _dev ) )
353 for (
const auto &_dev :
devices )
355 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
368 for (
const auto &_dev :
devices )
370 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU )
385 catch ( cl::Error &e )
387 QgsDebugMsg( QStringLiteral(
"Error %1 on platform %3 searching for OpenCL device: %2" )
389 QString::fromStdString( e.what() ),
390 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
402 cl::Platform newP = cl::Platform::setDefault( plat );
411 cl::Device::setDefault( dev );
413 .arg( QString::fromStdString( dev.getInfo<CL_DEVICE_NAME>() ) ),
420 catch ( cl::Error &e )
423 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
432 return QStringLiteral(
433 "Type: <b>%9</b><br>"
434 "Name: <b>%1</b><br>"
435 "Vendor: <b>%2</b><br>"
436 "Profile: <b>%3</b><br>"
437 "Version: <b>%4</b><br>"
438 "Image support: <b>%5</b><br>"
439 "Max image2d width: <b>%6</b><br>"
440 "Max image2d height: <b>%7</b><br>"
441 "Max mem alloc size: <b>%8</b><br>"
455 for (
const auto &dev :
devices( ) )
482 if ( file.open( QFile::ReadOnly | QFile::Text ) )
484 QTextStream in( &file );
485 source_str = in.readAll();
497 QString path = QStringLiteral(
"%1/%2.cl" ).arg(
sourcePath(), baseName );
503 cl::BuildLogType build_logs = error.getBuildLog();
505 if ( build_logs.size() > 0 )
506 build_log = QString::fromStdString( build_logs[0].second );
514 case 0:
return QStringLiteral(
"CL_SUCCESS" );
515 case -1:
return QStringLiteral(
"CL_DEVICE_NOT_FOUND" );
516 case -2:
return QStringLiteral(
"CL_DEVICE_NOT_AVAILABLE" );
517 case -3:
return QStringLiteral(
"CL_COMPILER_NOT_AVAILABLE" );
518 case -4:
return QStringLiteral(
"CL_MEM_OBJECT_ALLOCATION_FAILURE" );
519 case -5:
return QStringLiteral(
"CL_OUT_OF_RESOURCES" );
520 case -6:
return QStringLiteral(
"CL_OUT_OF_HOST_MEMORY" );
521 case -7:
return QStringLiteral(
"CL_PROFILING_INFO_NOT_AVAILABLE" );
522 case -8:
return QStringLiteral(
"CL_MEM_COPY_OVERLAP" );
523 case -9:
return QStringLiteral(
"CL_IMAGE_FORMAT_MISMATCH" );
524 case -10:
return QStringLiteral(
"CL_IMAGE_FORMAT_NOT_SUPPORTED" );
525 case -12:
return QStringLiteral(
"CL_MAP_FAILURE" );
526 case -13:
return QStringLiteral(
"CL_MISALIGNED_SUB_BUFFER_OFFSET" );
527 case -14:
return QStringLiteral(
"CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST" );
528 case -15:
return QStringLiteral(
"CL_COMPILE_PROGRAM_FAILURE" );
529 case -16:
return QStringLiteral(
"CL_LINKER_NOT_AVAILABLE" );
530 case -17:
return QStringLiteral(
"CL_LINK_PROGRAM_FAILURE" );
531 case -18:
return QStringLiteral(
"CL_DEVICE_PARTITION_FAILED" );
532 case -19:
return QStringLiteral(
"CL_KERNEL_ARG_INFO_NOT_AVAILABLE" );
533 case -30:
return QStringLiteral(
"CL_INVALID_VALUE" );
534 case -31:
return QStringLiteral(
"CL_INVALID_DEVICE_TYPE" );
535 case -32:
return QStringLiteral(
"CL_INVALID_PLATFORM" );
536 case -33:
return QStringLiteral(
"CL_INVALID_DEVICE" );
537 case -34:
return QStringLiteral(
"CL_INVALID_CONTEXT" );
538 case -35:
return QStringLiteral(
"CL_INVALID_QUEUE_PROPERTIES" );
539 case -36:
return QStringLiteral(
"CL_INVALID_COMMAND_QUEUE" );
540 case -37:
return QStringLiteral(
"CL_INVALID_HOST_PTR" );
541 case -38:
return QStringLiteral(
"CL_INVALID_MEM_OBJECT" );
542 case -39:
return QStringLiteral(
"CL_INVALID_IMAGE_FORMAT_DESCRIPTOR" );
543 case -40:
return QStringLiteral(
"CL_INVALID_IMAGE_SIZE" );
544 case -41:
return QStringLiteral(
"CL_INVALID_SAMPLER" );
545 case -42:
return QStringLiteral(
"CL_INVALID_BINARY" );
546 case -43:
return QStringLiteral(
"CL_INVALID_BUILD_OPTIONS" );
547 case -44:
return QStringLiteral(
"CL_INVALID_PROGRAM" );
548 case -45:
return QStringLiteral(
"CL_INVALID_PROGRAM_EXECUTABLE" );
549 case -46:
return QStringLiteral(
"CL_INVALID_KERNEL_NAME" );
550 case -47:
return QStringLiteral(
"CL_INVALID_KERNEL_DEFINITION" );
551 case -48:
return QStringLiteral(
"CL_INVALID_KERNEL" );
552 case -49:
return QStringLiteral(
"CL_INVALID_ARG_INDEX" );
553 case -50:
return QStringLiteral(
"CL_INVALID_ARG_VALUE" );
554 case -51:
return QStringLiteral(
"CL_INVALID_ARG_SIZE" );
555 case -52:
return QStringLiteral(
"CL_INVALID_KERNEL_ARGS" );
556 case -53:
return QStringLiteral(
"CL_INVALID_WORK_DIMENSION" );
557 case -54:
return QStringLiteral(
"CL_INVALID_WORK_GROUP_SIZE" );
558 case -55:
return QStringLiteral(
"CL_INVALID_WORK_ITEM_SIZE" );
559 case -56:
return QStringLiteral(
"CL_INVALID_GLOBAL_OFFSET" );
560 case -57:
return QStringLiteral(
"CL_INVALID_EVENT_WAIT_LIST" );
561 case -58:
return QStringLiteral(
"CL_INVALID_EVENT" );
562 case -59:
return QStringLiteral(
"CL_INVALID_OPERATION" );
563 case -60:
return QStringLiteral(
"CL_INVALID_GL_OBJECT" );
564 case -61:
return QStringLiteral(
"CL_INVALID_BUFFER_SIZE" );
565 case -62:
return QStringLiteral(
"CL_INVALID_MIP_LEVEL" );
566 case -63:
return QStringLiteral(
"CL_INVALID_GLOBAL_WORK_SIZE" );
567 case -64:
return QStringLiteral(
"CL_INVALID_PROPERTY" );
568 case -65:
return QStringLiteral(
"CL_INVALID_IMAGE_DESCRIPTOR" );
569 case -66:
return QStringLiteral(
"CL_INVALID_COMPILER_OPTIONS" );
570 case -67:
return QStringLiteral(
"CL_INVALID_LINKER_OPTIONS" );
571 case -68:
return QStringLiteral(
"CL_INVALID_DEVICE_PARTITION_COUNT" );
572 case -69:
return QStringLiteral(
"CL_INVALID_PIPE_SIZE" );
573 case -70:
return QStringLiteral(
"CL_INVALID_DEVICE_QUEUE" );
574 case -71:
return QStringLiteral(
"CL_INVALID_SPEC_ID" );
575 case -72:
return QStringLiteral(
"CL_MAX_SIZE_RESTRICTION_EXCEEDED" );
576 case -1002:
return QStringLiteral(
"CL_INVALID_D3D10_DEVICE_KHR" );
577 case -1003:
return QStringLiteral(
"CL_INVALID_D3D10_RESOURCE_KHR" );
578 case -1004:
return QStringLiteral(
"CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR" );
579 case -1005:
return QStringLiteral(
"CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR" );
580 case -1006:
return QStringLiteral(
"CL_INVALID_D3D11_DEVICE_KHR" );
581 case -1007:
return QStringLiteral(
"CL_INVALID_D3D11_RESOURCE_KHR" );
582 case -1008:
return QStringLiteral(
"CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR" );
583 case -1009:
return QStringLiteral(
"CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR" );
584 case -1010:
return QStringLiteral(
"CL_INVALID_DX9_MEDIA_ADAPTER_KHR" );
585 case -1011:
return QStringLiteral(
"CL_INVALID_DX9_MEDIA_SURFACE_KHR" );
586 case -1012:
return QStringLiteral(
"CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR" );
587 case -1013:
return QStringLiteral(
"CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR" );
588 case -1093:
return QStringLiteral(
"CL_INVALID_EGL_OBJECT_KHR" );
589 case -1092:
return QStringLiteral(
"CL_EGL_RESOURCE_NOT_ACQUIRED_KHR" );
590 case -1001:
return QStringLiteral(
"CL_PLATFORM_NOT_FOUND_KHR" );
591 case -1057:
return QStringLiteral(
"CL_DEVICE_PARTITION_FAILED_EXT" );
592 case -1058:
return QStringLiteral(
"CL_INVALID_PARTITION_COUNT_EXT" );
593 case -1059:
return QStringLiteral(
"CL_INVALID_PARTITION_NAME_EXT" );
594 case -1094:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_INTEL" );
595 case -1095:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_TYPE_INTEL" );
596 case -1096:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL" );
597 case -1097:
return QStringLiteral(
"CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL" );
598 case -1000:
return QStringLiteral(
"CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR" );
599 case -1098:
return QStringLiteral(
"CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL" );
600 case -1099:
return QStringLiteral(
"CL_INVALID_VA_API_MEDIA_SURFACE_INTEL" );
601 case -1100:
return QStringLiteral(
"CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL" );
602 case -1101:
return QStringLiteral(
"CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL" );
603 default:
return QStringLiteral(
"CL_UNKNOWN_ERROR" );
615 return cl::CommandQueue(
context );
620 cl_command_queue_properties properties = 0;
622 cl_command_queue queue = clCreateCommandQueue(
context(), device(), properties,
nullptr );
624 return cl::CommandQueue( queue,
true );
631 static std::once_flag contextCreated;
632 std::call_once( contextCreated, [ = ]()
634 if (
available() && cl::Platform::getDefault()() && cl::Device::getDefault()() )
636 context = cl::Context( cl::Device::getDefault() );
658 if ( ok && version < 2.0f )
660 program.build( QStringLiteral(
"-cl-std=CL%1 -I%2" )
666 program.build( QStringLiteral(
"-I%1" )
670 catch ( cl::BuildError &e )
673 if ( build_log.isEmpty() )
674 build_log = QObject::tr(
"Build logs not available!" );
675 QString err = QObject::tr(
"Error building OpenCL program: %1" )
678 if ( exceptionBehavior ==
Throw )
681 catch ( cl::Error &e )
683 QString err = QObject::tr(
"Error %1 building OpenCL program in %2" )
684 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) );