23 #include <QTextStream> 32 QLatin1String QgsOpenClUtils::SETTINGS_GLOBAL_ENABLED_KEY = QLatin1Literal(
"OpenClEnabled" );
33 QLatin1String QgsOpenClUtils::SETTINGS_DEFAULT_DEVICE_KEY = QLatin1Literal(
"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();
291 QgsSettings().
setValue( SETTINGS_DEFAULT_DEVICE_KEY, deviceId, QgsSettings::Section::Core );
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( ) )
471 QgsSettings().
setValue( SETTINGS_GLOBAL_ENABLED_KEY, enabled, QgsSettings::Section::Core );
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() ) );
static QString sourcePath()
Returns the base path to OpenCL program directory.
static QString deviceId(const cl::Device device)
Create a string identifier from a device.
static void setEnabled(bool enabled)
Set the OpenCL user setting to enabled.
static QString sourceFromBaseName(const QString &baseName)
Returns the full path to a an OpenCL source file from the baseName ('.cl' extension is automatically ...
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define Q_NOWARN_DEPRECATED_PUSH
static void storePreferredDevice(const QString deviceId)
Store in the settings the preferred deviceId device identifier.
static bool available()
Checks whether a suitable OpenCL platform and device is available on this system and initialize the Q...
The QgsOpenClUtils class is responsible for common OpenCL operations such as.
static const std::vector< cl::Device > devices()
Returns a list of OpenCL devices found on this sysytem.
static cl::Context context()
Context factory.
static QString deviceDescription(const cl::Device device)
Returns a formatted description for the device.
Info
The Info enum maps to OpenCL info constants.
ExceptionBehavior
The ExceptionBehavior enum define how exceptions generated by OpenCL should be treated.
static QString activePlatformVersion()
Returns the active platform OpenCL version string (e.g.
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define QgsDebugMsgLevel(str, level)
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static bool enabled()
Returns true if OpenCL is enabled in the user settings.
static QString sourceFromPath(const QString &path)
Read an OpenCL source file from path.
static void setSourcePath(const QString &value)
Set the base path to OpenCL program directory.
static cl::Device activeDevice()
Returns the active device.
Write errors in the message log and re-throw exceptions.
static QString errorText(const int errorCode)
Returns a string representation from an OpenCL errorCode.
static QString buildLog(cl::BuildError &error)
Extract and return the build log error from error.
static Q_DECL_DEPRECATED cl::Program buildProgram(const cl::Context &context, const QString &source, ExceptionBehavior exceptionBehavior=Catch)
Build the program from source in the given context and depending on exceptionBehavior can throw or ca...
#define Q_NOWARN_DEPRECATED_POP
static QLatin1String LOGMESSAGE_TAG
OpenCL string for message logs.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QString deviceInfo(const Info infoType, cl::Device device)
Returns infoType information about the device.
static QString preferredDevice()
Read from the settings the preferred device identifier.
static cl::CommandQueue commandQueue()
Create an OpenCL command queue from the default context.
static QString activeDeviceInfo(const Info infoType=Info::Name)
Returns infoType information about the active (default) device.