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;
36 QString QgsOpenClUtils::sSourcePath = QString();
41 std::vector<cl::Platform> platforms;
42 cl::Platform::get( &platforms );
43 std::vector<cl::Device> existingDevices;
44 for (
auto &p : platforms )
46 std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
48 .arg( QString::fromStdString( platver ),
49 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
51 if ( platver.find(
"OpenCL " ) != std::string::npos )
53 std::vector<cl::Device> _devices;
57 p.getDevices( CL_DEVICE_TYPE_ALL, &_devices );
59 catch ( cl::Error &e )
63 QString::fromStdString( e.what() ),
64 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
LOGMESSAGE_TAG );
66 if ( _devices.size() > 0 )
68 for (
unsigned long i = 0; i < _devices.size(); i++ )
72 existingDevices.push_back( _devices[i] );
77 return existingDevices;
80 void QgsOpenClUtils::init()
82 static std::once_flag initialized;
83 std::call_once( initialized, [ = ]( )
85 QLibrary openCLLib{ QStringLiteral(
"OpenCL" ) };
86 openCLLib.setLoadHints( QLibrary::LoadHint::ResolveAllSymbolsHint );
87 if ( ! openCLLib.load() )
90 .arg( openCLLib.errorString() ),
96 HMODULE hModule = GetModuleHandle(
"OpenCL.dll" );
99 TCHAR pszFileName[1024];
100 if ( GetModuleFileName( hModule, pszFileName, 1024 ) < 1024 )
105 DWORD dwLen = GetFileVersionInfoSize( pszFileName, &dwUseless );
108 LPTSTR lpVI = ( LPSTR ) malloc( dwLen );
111 if ( GetFileVersionInfo( pszFileName, NULL, dwLen, lpVI ) )
113 VS_FIXEDFILEINFO *lpFFI;
114 if ( VerQueryValue( lpVI,
"\\", ( LPVOID * ) &lpFFI, ( UINT * ) &dwUseless ) )
117 .arg( lpFFI->dwProductVersionMS >> 16 )
118 .arg( lpFFI->dwProductVersionMS & 0xffff )
119 .arg( lpFFI->dwProductVersionLS >> 16 )
123 struct LANGANDCODEPAGE
131 if ( VerQueryValue( lpVI, _T(
"\\VarFileInfo\\Translation" ), ( LPVOID * ) &lpTranslate, ( UINT * ) &cbTranslate ) && cbTranslate >=
sizeof(
struct LANGANDCODEPAGE ) )
133 QStringList items = QStringList()
134 << QStringLiteral(
"Comments" )
135 << QStringLiteral(
"InternalName" )
136 << QStringLiteral(
"ProductName" )
137 << QStringLiteral(
"CompanyName" )
138 << QStringLiteral(
"LegalCopyright" )
139 << QStringLiteral(
"ProductVersion" )
140 << QStringLiteral(
"FileDescription" )
141 << QStringLiteral(
"LegalTrademarks" )
142 << QStringLiteral(
"PrivateBuild" )
143 << QStringLiteral(
"FileVersion" )
144 << QStringLiteral(
"OriginalFilename" )
145 << QStringLiteral(
"SpecialBuild" );
146 for (
auto d : items )
149 QString subBlock = QString( QStringLiteral(
"\\StringFileInfo\\%1%2\\%3" ) )
150 .arg( lpTranslate[0].wLanguage, 4, 16, QLatin1Char(
'0' ) )
151 .arg( lpTranslate[0].wCodePage, 4, 16, QLatin1Char(
'0' ) )
154 QgsDebugMsg( QString(
"d:%1 subBlock:%2" ).arg( d ).arg( subBlock ) );
156 BOOL r = VerQueryValue( lpVI, subBlock.toUtf8(), ( LPVOID * )&lpBuffer, ( UINT * )&dwUseless );
158 if ( r && lpBuffer && lpBuffer != INVALID_HANDLE_VALUE && dwUseless < 1023 )
185 catch ( cl::Error &e )
188 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
217 return QString::fromStdString( device.getInfo<CL_DEVICE_VENDOR>() );
219 return QString::fromStdString( device.getInfo<CL_DEVICE_PROFILE>() );
221 return QString::fromStdString( device.getInfo<CL_DEVICE_VERSION>() );
222 case Info::ImageSupport:
223 return device.getInfo<CL_DEVICE_IMAGE_SUPPORT>() ? QStringLiteral(
"True" ) : QStringLiteral(
"False" );
224 case Info::Image2dMaxHeight:
225 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>() );
226 case Info::MaxMemAllocSize:
227 return QString::number( device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() );
228 case Info::Image2dMaxWidth:
229 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() );
232 unsigned long type( device.getInfo<CL_DEVICE_TYPE>() );
236 case CL_DEVICE_TYPE_CPU:
237 mappedType = QgsOpenClUtils::HardwareType::CPU;
239 case CL_DEVICE_TYPE_GPU:
240 mappedType = QgsOpenClUtils::HardwareType::GPU;
243 mappedType = QgsOpenClUtils::HardwareType::Other;
245 QMetaEnum metaEnum = QMetaEnum::fromType<QgsOpenClUtils::HardwareType>();
246 return metaEnum.valueToKey( mappedType );
249 return QString::fromStdString( device.getInfo<CL_DEVICE_NAME>() );
252 catch ( cl::Error &e )
255 QgsDebugMsgLevel( QStringLiteral(
"Error %1 getting info for OpenCL device: %2" )
256 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
266 return QgsSettings().
value( SETTINGS_GLOBAL_ENABLED_KEY,
false, QgsSettings::Section::Core ).toBool();
271 return cl::Device::getDefault();
277 if ( cl::Platform::getDefault()() )
279 std::string platver = cl::Platform::getDefault().getInfo<CL_PLATFORM_VERSION>();
280 if ( platver.find(
"OpenCL " ) != std::string::npos )
282 version = QString::fromStdString( platver.substr( 7 ) ).split(
' ' ).first();
290 QgsSettings().
setValue( SETTINGS_DEFAULT_DEVICE_KEY, deviceId, QgsSettings::Section::Core );
295 return QgsSettings().
value( SETTINGS_DEFAULT_DEVICE_KEY, QString( ), QgsSettings::Section::Core ).toString();
300 return QStringLiteral(
"%1|%2|%3|%4" )
301 .arg(
deviceInfo( QgsOpenClUtils::Info::Name, device ) )
302 .arg(
deviceInfo( QgsOpenClUtils::Info::Vendor, device ) )
303 .arg(
deviceInfo( QgsOpenClUtils::Info::Version, device ) )
304 .arg(
deviceInfo( QgsOpenClUtils::Info::Type, device ) );
307 bool QgsOpenClUtils::activate(
const QString &preferredDeviceId )
316 std::vector<cl::Platform> platforms;
317 cl::Platform::get( &platforms );
320 bool deviceFound =
false;
321 for (
auto &p : platforms )
325 std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
326 QgsDebugMsg( QStringLiteral(
"Found OpenCL platform %1: %2" ).arg( QString::fromStdString( platver ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
327 if ( platver.find(
"OpenCL " ) != std::string::npos )
329 std::vector<cl::Device>
devices;
333 p.getDevices( CL_DEVICE_TYPE_ALL, &devices );
335 if ( ! preferredDeviceId.isEmpty() )
337 for (
const auto &_dev : devices )
339 if ( preferredDeviceId ==
deviceId( _dev ) )
352 for (
const auto &_dev : devices )
354 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
367 for (
const auto &_dev : devices )
369 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU )
384 catch ( cl::Error &e )
386 QgsDebugMsg( QStringLiteral(
"Error %1 on platform %3 searching for OpenCL device: %2" )
388 QString::fromStdString( e.what() ),
389 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
401 cl::Platform newP = cl::Platform::setDefault( plat );
410 cl::Device::setDefault( dev );
412 .arg( QString::fromStdString( dev.getInfo<CL_DEVICE_NAME>() ) ),
419 catch ( cl::Error &e )
422 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
431 return QStringLiteral(
432 "Type: <b>%9</b><br>" 433 "Name: <b>%1</b><br>" 434 "Vendor: <b>%2</b><br>" 435 "Profile: <b>%3</b><br>" 436 "Version: <b>%4</b><br>" 437 "Image support: <b>%5</b><br>" 438 "Max image2d width: <b>%6</b><br>" 439 "Max image2d height: <b>%7</b><br>" 440 "Max mem alloc size: <b>%8</b><br>" 454 for (
const auto &dev :
devices( ) )
470 QgsSettings().
setValue( SETTINGS_GLOBAL_ENABLED_KEY, enabled, QgsSettings::Section::Core );
481 if ( file.open( QFile::ReadOnly | QFile::Text ) )
483 QTextStream in( &file );
484 source_str = in.readAll();
496 QString path = QStringLiteral(
"%1/%2.cl" ).arg(
sourcePath(), baseName );
502 cl::BuildLogType build_logs = error.getBuildLog();
504 if ( build_logs.size() > 0 )
505 build_log = QString::fromStdString( build_logs[0].second );
513 case 0:
return QStringLiteral(
"CL_SUCCESS" );
514 case -1:
return QStringLiteral(
"CL_DEVICE_NOT_FOUND" );
515 case -2:
return QStringLiteral(
"CL_DEVICE_NOT_AVAILABLE" );
516 case -3:
return QStringLiteral(
"CL_COMPILER_NOT_AVAILABLE" );
517 case -4:
return QStringLiteral(
"CL_MEM_OBJECT_ALLOCATION_FAILURE" );
518 case -5:
return QStringLiteral(
"CL_OUT_OF_RESOURCES" );
519 case -6:
return QStringLiteral(
"CL_OUT_OF_HOST_MEMORY" );
520 case -7:
return QStringLiteral(
"CL_PROFILING_INFO_NOT_AVAILABLE" );
521 case -8:
return QStringLiteral(
"CL_MEM_COPY_OVERLAP" );
522 case -9:
return QStringLiteral(
"CL_IMAGE_FORMAT_MISMATCH" );
523 case -10:
return QStringLiteral(
"CL_IMAGE_FORMAT_NOT_SUPPORTED" );
524 case -12:
return QStringLiteral(
"CL_MAP_FAILURE" );
525 case -13:
return QStringLiteral(
"CL_MISALIGNED_SUB_BUFFER_OFFSET" );
526 case -14:
return QStringLiteral(
"CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST" );
527 case -15:
return QStringLiteral(
"CL_COMPILE_PROGRAM_FAILURE" );
528 case -16:
return QStringLiteral(
"CL_LINKER_NOT_AVAILABLE" );
529 case -17:
return QStringLiteral(
"CL_LINK_PROGRAM_FAILURE" );
530 case -18:
return QStringLiteral(
"CL_DEVICE_PARTITION_FAILED" );
531 case -19:
return QStringLiteral(
"CL_KERNEL_ARG_INFO_NOT_AVAILABLE" );
532 case -30:
return QStringLiteral(
"CL_INVALID_VALUE" );
533 case -31:
return QStringLiteral(
"CL_INVALID_DEVICE_TYPE" );
534 case -32:
return QStringLiteral(
"CL_INVALID_PLATFORM" );
535 case -33:
return QStringLiteral(
"CL_INVALID_DEVICE" );
536 case -34:
return QStringLiteral(
"CL_INVALID_CONTEXT" );
537 case -35:
return QStringLiteral(
"CL_INVALID_QUEUE_PROPERTIES" );
538 case -36:
return QStringLiteral(
"CL_INVALID_COMMAND_QUEUE" );
539 case -37:
return QStringLiteral(
"CL_INVALID_HOST_PTR" );
540 case -38:
return QStringLiteral(
"CL_INVALID_MEM_OBJECT" );
541 case -39:
return QStringLiteral(
"CL_INVALID_IMAGE_FORMAT_DESCRIPTOR" );
542 case -40:
return QStringLiteral(
"CL_INVALID_IMAGE_SIZE" );
543 case -41:
return QStringLiteral(
"CL_INVALID_SAMPLER" );
544 case -42:
return QStringLiteral(
"CL_INVALID_BINARY" );
545 case -43:
return QStringLiteral(
"CL_INVALID_BUILD_OPTIONS" );
546 case -44:
return QStringLiteral(
"CL_INVALID_PROGRAM" );
547 case -45:
return QStringLiteral(
"CL_INVALID_PROGRAM_EXECUTABLE" );
548 case -46:
return QStringLiteral(
"CL_INVALID_KERNEL_NAME" );
549 case -47:
return QStringLiteral(
"CL_INVALID_KERNEL_DEFINITION" );
550 case -48:
return QStringLiteral(
"CL_INVALID_KERNEL" );
551 case -49:
return QStringLiteral(
"CL_INVALID_ARG_INDEX" );
552 case -50:
return QStringLiteral(
"CL_INVALID_ARG_VALUE" );
553 case -51:
return QStringLiteral(
"CL_INVALID_ARG_SIZE" );
554 case -52:
return QStringLiteral(
"CL_INVALID_KERNEL_ARGS" );
555 case -53:
return QStringLiteral(
"CL_INVALID_WORK_DIMENSION" );
556 case -54:
return QStringLiteral(
"CL_INVALID_WORK_GROUP_SIZE" );
557 case -55:
return QStringLiteral(
"CL_INVALID_WORK_ITEM_SIZE" );
558 case -56:
return QStringLiteral(
"CL_INVALID_GLOBAL_OFFSET" );
559 case -57:
return QStringLiteral(
"CL_INVALID_EVENT_WAIT_LIST" );
560 case -58:
return QStringLiteral(
"CL_INVALID_EVENT" );
561 case -59:
return QStringLiteral(
"CL_INVALID_OPERATION" );
562 case -60:
return QStringLiteral(
"CL_INVALID_GL_OBJECT" );
563 case -61:
return QStringLiteral(
"CL_INVALID_BUFFER_SIZE" );
564 case -62:
return QStringLiteral(
"CL_INVALID_MIP_LEVEL" );
565 case -63:
return QStringLiteral(
"CL_INVALID_GLOBAL_WORK_SIZE" );
566 case -64:
return QStringLiteral(
"CL_INVALID_PROPERTY" );
567 case -65:
return QStringLiteral(
"CL_INVALID_IMAGE_DESCRIPTOR" );
568 case -66:
return QStringLiteral(
"CL_INVALID_COMPILER_OPTIONS" );
569 case -67:
return QStringLiteral(
"CL_INVALID_LINKER_OPTIONS" );
570 case -68:
return QStringLiteral(
"CL_INVALID_DEVICE_PARTITION_COUNT" );
571 case -69:
return QStringLiteral(
"CL_INVALID_PIPE_SIZE" );
572 case -70:
return QStringLiteral(
"CL_INVALID_DEVICE_QUEUE" );
573 case -71:
return QStringLiteral(
"CL_INVALID_SPEC_ID" );
574 case -72:
return QStringLiteral(
"CL_MAX_SIZE_RESTRICTION_EXCEEDED" );
575 case -1002:
return QStringLiteral(
"CL_INVALID_D3D10_DEVICE_KHR" );
576 case -1003:
return QStringLiteral(
"CL_INVALID_D3D10_RESOURCE_KHR" );
577 case -1004:
return QStringLiteral(
"CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR" );
578 case -1005:
return QStringLiteral(
"CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR" );
579 case -1006:
return QStringLiteral(
"CL_INVALID_D3D11_DEVICE_KHR" );
580 case -1007:
return QStringLiteral(
"CL_INVALID_D3D11_RESOURCE_KHR" );
581 case -1008:
return QStringLiteral(
"CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR" );
582 case -1009:
return QStringLiteral(
"CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR" );
583 case -1010:
return QStringLiteral(
"CL_INVALID_DX9_MEDIA_ADAPTER_KHR" );
584 case -1011:
return QStringLiteral(
"CL_INVALID_DX9_MEDIA_SURFACE_KHR" );
585 case -1012:
return QStringLiteral(
"CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR" );
586 case -1013:
return QStringLiteral(
"CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR" );
587 case -1093:
return QStringLiteral(
"CL_INVALID_EGL_OBJECT_KHR" );
588 case -1092:
return QStringLiteral(
"CL_EGL_RESOURCE_NOT_ACQUIRED_KHR" );
589 case -1001:
return QStringLiteral(
"CL_PLATFORM_NOT_FOUND_KHR" );
590 case -1057:
return QStringLiteral(
"CL_DEVICE_PARTITION_FAILED_EXT" );
591 case -1058:
return QStringLiteral(
"CL_INVALID_PARTITION_COUNT_EXT" );
592 case -1059:
return QStringLiteral(
"CL_INVALID_PARTITION_NAME_EXT" );
593 case -1094:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_INTEL" );
594 case -1095:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_TYPE_INTEL" );
595 case -1096:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL" );
596 case -1097:
return QStringLiteral(
"CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL" );
597 case -1000:
return QStringLiteral(
"CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR" );
598 case -1098:
return QStringLiteral(
"CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL" );
599 case -1099:
return QStringLiteral(
"CL_INVALID_VA_API_MEDIA_SURFACE_INTEL" );
600 case -1100:
return QStringLiteral(
"CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL" );
601 case -1101:
return QStringLiteral(
"CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL" );
602 default:
return QStringLiteral(
"CL_UNKNOWN_ERROR" );
614 return cl::CommandQueue( context );
619 cl_command_queue_properties properties = 0;
621 cl_command_queue queue = clCreateCommandQueue(
context(), device(), properties,
nullptr );
623 return cl::CommandQueue( queue,
true );
630 static std::once_flag contextCreated;
631 std::call_once( contextCreated, [ = ]()
633 if (
available() && cl::Platform::getDefault()() && cl::Device::getDefault()() )
635 context = cl::Context( cl::Device::getDefault() );
657 if ( ok && version < 2.0f )
659 program.build( QStringLiteral(
"-cl-std=CL%1 -I%2" )
665 program.build( QStringLiteral(
"-I%1" )
669 catch ( cl::BuildError &e )
672 if ( build_log.isEmpty() )
673 build_log = QObject::tr(
"Build logs not available!" );
674 QString err = QObject::tr(
"Error building OpenCL program: %1" )
677 if ( exceptionBehavior ==
Throw )
680 catch ( cl::Error &e )
682 QString err = QObject::tr(
"Error %1 building OpenCL program in %2" )
683 .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...
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.
#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.