17#include "moc_qgsopenclutils.cpp"
29#if defined(UNICODE) && !defined(_UNICODE)
36QLatin1String QgsOpenClUtils::SETTINGS_GLOBAL_ENABLED_KEY = QLatin1String(
"OpenClEnabled" );
37QLatin1String QgsOpenClUtils::SETTINGS_DEFAULT_DEVICE_KEY = QLatin1String(
"OpenClDefaultDevice" );
39bool QgsOpenClUtils::sAvailable =
false;
46 std::vector<cl::Platform> platforms;
47 cl::Platform::get( &platforms );
48 std::vector<cl::Device> existingDevices;
49 for (
const auto &p : platforms )
51 const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
53 .arg( QString::fromStdString( platver ),
54 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
56 if ( platver.find(
"OpenCL " ) != std::string::npos )
58 std::vector<cl::Device> _devices;
62 p.getDevices( CL_DEVICE_TYPE_ALL, &_devices );
64 catch ( cl::Error &e )
67 .arg( errorText( e.err() ),
68 QString::fromStdString( e.what() ),
69 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
72 if ( _devices.size() > 0 )
74 for (
unsigned long i = 0; i < _devices.size(); i++ )
77 .arg( deviceId( _devices[i] ) ),
79 existingDevices.push_back( _devices[i] );
84 return existingDevices;
87void QgsOpenClUtils::init()
89 static std::once_flag initialized;
90 std::call_once( initialized, [ = ]( )
93 QLibrary openCLLib { QStringLiteral(
"/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL" ) };
95 QLibrary openCLLib { QStringLiteral(
"OpenCL" ) };
97 openCLLib.setLoadHints( QLibrary::LoadHint::ResolveAllSymbolsHint );
98 if ( ! openCLLib.load() )
101 .arg( openCLLib.errorString() ),
112 HMODULE hModule = GetModuleHandle( _T(
"OpenCL.dll" ) );
115 TCHAR pszFileName[1024];
116 if ( GetModuleFileName( hModule, pszFileName, 1024 ) < 1024 )
123 DWORD dwLen = GetFileVersionInfoSize( pszFileName, &dwUseless );
126 LPTSTR lpVI = ( LPTSTR ) malloc( dwLen *
sizeof( TCHAR ) );
129 if ( GetFileVersionInfo( pszFileName, 0, dwLen, lpVI ) )
131 VS_FIXEDFILEINFO *lpFFI;
132 if ( VerQueryValue( lpVI, _T(
"\\" ), ( LPVOID * ) &lpFFI, ( UINT * ) &dwUseless ) )
135 .arg( lpFFI->dwProductVersionMS >> 16 )
136 .arg( lpFFI->dwProductVersionMS & 0xffff )
137 .arg( lpFFI->dwProductVersionLS >> 16 )
138 .arg( lpFFI->dwProductVersionLS & 0xffff ),
142 struct LANGANDCODEPAGE
150 if ( VerQueryValue( lpVI, _T(
"\\VarFileInfo\\Translation" ), ( LPVOID * ) &lpTranslate, ( UINT * ) &cbTranslate ) && cbTranslate >=
sizeof(
struct LANGANDCODEPAGE ) )
152 QStringList items = QStringList()
153 << QStringLiteral(
"Comments" )
154 << QStringLiteral(
"InternalName" )
155 << QStringLiteral(
"ProductName" )
156 << QStringLiteral(
"CompanyName" )
157 << QStringLiteral(
"LegalCopyright" )
158 << QStringLiteral(
"ProductVersion" )
159 << QStringLiteral(
"FileDescription" )
160 << QStringLiteral(
"LegalTrademarks" )
161 << QStringLiteral(
"PrivateBuild" )
162 << QStringLiteral(
"FileVersion" )
163 << QStringLiteral(
"OriginalFilename" )
164 << QStringLiteral(
"SpecialBuild" );
165 for (
auto d : items )
168 QString subBlock = QString( QStringLiteral(
"\\StringFileInfo\\%1%2\\%3" ) )
169 .arg( lpTranslate[0].wLanguage, 4, 16, QLatin1Char(
'0' ) )
170 .arg( lpTranslate[0].wCodePage, 4, 16, QLatin1Char(
'0' ) )
173 QgsDebugMsgLevel( QString(
"d:%1 subBlock:%2" ).arg( d ).arg( subBlock ), 2 );
175 BOOL r = VerQueryValue( lpVI,
177 subBlock.toStdWString().c_str(),
181 ( LPVOID * )&lpBuffer, ( UINT * )&dwUseless );
183 if ( r && lpBuffer && lpBuffer != INVALID_HANDLE_VALUE && dwUseless < 1023 )
188 .arg( QString::fromUtf16( (
const ushort * ) lpBuffer ) ),
190 .arg( QString::fromLocal8Bit( lpBuffer ) ),
217 catch ( cl::Error &e )
220 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
229 return *sSourcePath();
234 *sSourcePath() = value;
249 return QString::fromStdString( device.getInfo<CL_DEVICE_VENDOR>() );
251 return QString::fromStdString( device.getInfo<CL_DEVICE_PROFILE>() );
253 return QString::fromStdString( device.getInfo<CL_DEVICE_VERSION>() );
255 return device.getInfo<CL_DEVICE_IMAGE_SUPPORT>() ? QStringLiteral(
"True" ) : QStringLiteral(
"False" );
257 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>() );
259 return QString::number( device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() );
261 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() );
264 const unsigned long type( device.getInfo<CL_DEVICE_TYPE>() );
268 case CL_DEVICE_TYPE_CPU:
271 case CL_DEVICE_TYPE_GPU:
277 const QMetaEnum metaEnum = QMetaEnum::fromType<QgsOpenClUtils::HardwareType>();
278 return metaEnum.valueToKey( mappedType );
281 return QString::fromStdString( device.getInfo<CL_DEVICE_NAME>() );
284 catch ( cl::Error &e )
287 QgsDebugMsgLevel( QStringLiteral(
"Error %1 getting info for OpenCL device: %2" )
288 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
303 return cl::Device::getDefault();
309 if ( cl::Platform::getDefault()() )
311 const std::string platver = cl::Platform::getDefault().getInfo<CL_PLATFORM_VERSION>();
312 if ( platver.find(
"OpenCL " ) != std::string::npos )
314 version = QString::fromStdString( platver.substr( 7 ) ).split(
' ' ).first();
332 return QStringLiteral(
"%1|%2|%3|%4" )
339bool QgsOpenClUtils::activate(
const QString &preferredDeviceId )
348 std::vector<cl::Platform> platforms;
349 cl::Platform::get( &platforms );
352 bool deviceFound =
false;
353 for (
const auto &p : platforms )
357 const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
358 QgsDebugMsgLevel( QStringLiteral(
"Found OpenCL platform %1: %2" ).arg( QString::fromStdString( platver ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ), 2 );
359 if ( platver.find(
"OpenCL " ) != std::string::npos )
361 std::vector<cl::Device>
devices;
365 p.getDevices( CL_DEVICE_TYPE_ALL, &
devices );
367 if ( ! preferredDeviceId.isEmpty() )
369 for (
const auto &_dev :
devices )
371 if ( preferredDeviceId ==
deviceId( _dev ) )
384 for (
const auto &_dev :
devices )
386 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
399 for (
const auto &_dev :
devices )
401 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU )
416 catch ( cl::Error &e )
418 QgsDebugError( QStringLiteral(
"Error %1 on platform %3 searching for OpenCL device: %2" )
420 QString::fromStdString( e.what() ),
421 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
433 const cl::Platform newP = cl::Platform::setDefault( plat );
442 cl::Device::setDefault( dev );
444 .arg( QString::fromStdString( dev.getInfo<CL_DEVICE_NAME>() ) ),
451 catch ( cl::Error &e )
454 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
463 return QStringLiteral(
464 "Type: <b>%9</b><br>"
465 "Name: <b>%1</b><br>"
466 "Vendor: <b>%2</b><br>"
467 "Profile: <b>%3</b><br>"
468 "Version: <b>%4</b><br>"
469 "Image support: <b>%5</b><br>"
470 "Max image2d width: <b>%6</b><br>"
471 "Max image2d height: <b>%7</b><br>"
472 "Max mem alloc size: <b>%8</b><br>"
486 for (
const auto &dev :
devices( ) )
513 if ( file.open( QFile::ReadOnly | QFile::Text ) )
515 QTextStream in( &file );
516 source_str = in.readAll();
528 const QString path = QStringLiteral(
"%1/%2.cl" ).arg(
sourcePath(), baseName );
534 cl::BuildLogType build_logs = error.getBuildLog();
536 if ( build_logs.size() > 0 )
537 build_log = QString::fromStdString( build_logs[0].second );
545 case 0:
return QStringLiteral(
"CL_SUCCESS" );
546 case -1:
return QStringLiteral(
"CL_DEVICE_NOT_FOUND" );
547 case -2:
return QStringLiteral(
"CL_DEVICE_NOT_AVAILABLE" );
548 case -3:
return QStringLiteral(
"CL_COMPILER_NOT_AVAILABLE" );
549 case -4:
return QStringLiteral(
"CL_MEM_OBJECT_ALLOCATION_FAILURE" );
550 case -5:
return QStringLiteral(
"CL_OUT_OF_RESOURCES" );
551 case -6:
return QStringLiteral(
"CL_OUT_OF_HOST_MEMORY" );
552 case -7:
return QStringLiteral(
"CL_PROFILING_INFO_NOT_AVAILABLE" );
553 case -8:
return QStringLiteral(
"CL_MEM_COPY_OVERLAP" );
554 case -9:
return QStringLiteral(
"CL_IMAGE_FORMAT_MISMATCH" );
555 case -10:
return QStringLiteral(
"CL_IMAGE_FORMAT_NOT_SUPPORTED" );
556 case -12:
return QStringLiteral(
"CL_MAP_FAILURE" );
557 case -13:
return QStringLiteral(
"CL_MISALIGNED_SUB_BUFFER_OFFSET" );
558 case -14:
return QStringLiteral(
"CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST" );
559 case -15:
return QStringLiteral(
"CL_COMPILE_PROGRAM_FAILURE" );
560 case -16:
return QStringLiteral(
"CL_LINKER_NOT_AVAILABLE" );
561 case -17:
return QStringLiteral(
"CL_LINK_PROGRAM_FAILURE" );
562 case -18:
return QStringLiteral(
"CL_DEVICE_PARTITION_FAILED" );
563 case -19:
return QStringLiteral(
"CL_KERNEL_ARG_INFO_NOT_AVAILABLE" );
564 case -30:
return QStringLiteral(
"CL_INVALID_VALUE" );
565 case -31:
return QStringLiteral(
"CL_INVALID_DEVICE_TYPE" );
566 case -32:
return QStringLiteral(
"CL_INVALID_PLATFORM" );
567 case -33:
return QStringLiteral(
"CL_INVALID_DEVICE" );
568 case -34:
return QStringLiteral(
"CL_INVALID_CONTEXT" );
569 case -35:
return QStringLiteral(
"CL_INVALID_QUEUE_PROPERTIES" );
570 case -36:
return QStringLiteral(
"CL_INVALID_COMMAND_QUEUE" );
571 case -37:
return QStringLiteral(
"CL_INVALID_HOST_PTR" );
572 case -38:
return QStringLiteral(
"CL_INVALID_MEM_OBJECT" );
573 case -39:
return QStringLiteral(
"CL_INVALID_IMAGE_FORMAT_DESCRIPTOR" );
574 case -40:
return QStringLiteral(
"CL_INVALID_IMAGE_SIZE" );
575 case -41:
return QStringLiteral(
"CL_INVALID_SAMPLER" );
576 case -42:
return QStringLiteral(
"CL_INVALID_BINARY" );
577 case -43:
return QStringLiteral(
"CL_INVALID_BUILD_OPTIONS" );
578 case -44:
return QStringLiteral(
"CL_INVALID_PROGRAM" );
579 case -45:
return QStringLiteral(
"CL_INVALID_PROGRAM_EXECUTABLE" );
580 case -46:
return QStringLiteral(
"CL_INVALID_KERNEL_NAME" );
581 case -47:
return QStringLiteral(
"CL_INVALID_KERNEL_DEFINITION" );
582 case -48:
return QStringLiteral(
"CL_INVALID_KERNEL" );
583 case -49:
return QStringLiteral(
"CL_INVALID_ARG_INDEX" );
584 case -50:
return QStringLiteral(
"CL_INVALID_ARG_VALUE" );
585 case -51:
return QStringLiteral(
"CL_INVALID_ARG_SIZE" );
586 case -52:
return QStringLiteral(
"CL_INVALID_KERNEL_ARGS" );
587 case -53:
return QStringLiteral(
"CL_INVALID_WORK_DIMENSION" );
588 case -54:
return QStringLiteral(
"CL_INVALID_WORK_GROUP_SIZE" );
589 case -55:
return QStringLiteral(
"CL_INVALID_WORK_ITEM_SIZE" );
590 case -56:
return QStringLiteral(
"CL_INVALID_GLOBAL_OFFSET" );
591 case -57:
return QStringLiteral(
"CL_INVALID_EVENT_WAIT_LIST" );
592 case -58:
return QStringLiteral(
"CL_INVALID_EVENT" );
593 case -59:
return QStringLiteral(
"CL_INVALID_OPERATION" );
594 case -60:
return QStringLiteral(
"CL_INVALID_GL_OBJECT" );
595 case -61:
return QStringLiteral(
"CL_INVALID_BUFFER_SIZE" );
596 case -62:
return QStringLiteral(
"CL_INVALID_MIP_LEVEL" );
597 case -63:
return QStringLiteral(
"CL_INVALID_GLOBAL_WORK_SIZE" );
598 case -64:
return QStringLiteral(
"CL_INVALID_PROPERTY" );
599 case -65:
return QStringLiteral(
"CL_INVALID_IMAGE_DESCRIPTOR" );
600 case -66:
return QStringLiteral(
"CL_INVALID_COMPILER_OPTIONS" );
601 case -67:
return QStringLiteral(
"CL_INVALID_LINKER_OPTIONS" );
602 case -68:
return QStringLiteral(
"CL_INVALID_DEVICE_PARTITION_COUNT" );
603 case -69:
return QStringLiteral(
"CL_INVALID_PIPE_SIZE" );
604 case -70:
return QStringLiteral(
"CL_INVALID_DEVICE_QUEUE" );
605 case -71:
return QStringLiteral(
"CL_INVALID_SPEC_ID" );
606 case -72:
return QStringLiteral(
"CL_MAX_SIZE_RESTRICTION_EXCEEDED" );
607 case -1002:
return QStringLiteral(
"CL_INVALID_D3D10_DEVICE_KHR" );
608 case -1003:
return QStringLiteral(
"CL_INVALID_D3D10_RESOURCE_KHR" );
609 case -1004:
return QStringLiteral(
"CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR" );
610 case -1005:
return QStringLiteral(
"CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR" );
611 case -1006:
return QStringLiteral(
"CL_INVALID_D3D11_DEVICE_KHR" );
612 case -1007:
return QStringLiteral(
"CL_INVALID_D3D11_RESOURCE_KHR" );
613 case -1008:
return QStringLiteral(
"CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR" );
614 case -1009:
return QStringLiteral(
"CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR" );
615 case -1010:
return QStringLiteral(
"CL_INVALID_DX9_MEDIA_ADAPTER_KHR" );
616 case -1011:
return QStringLiteral(
"CL_INVALID_DX9_MEDIA_SURFACE_KHR" );
617 case -1012:
return QStringLiteral(
"CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR" );
618 case -1013:
return QStringLiteral(
"CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR" );
619 case -1093:
return QStringLiteral(
"CL_INVALID_EGL_OBJECT_KHR" );
620 case -1092:
return QStringLiteral(
"CL_EGL_RESOURCE_NOT_ACQUIRED_KHR" );
621 case -1001:
return QStringLiteral(
"CL_PLATFORM_NOT_FOUND_KHR" );
622 case -1057:
return QStringLiteral(
"CL_DEVICE_PARTITION_FAILED_EXT" );
623 case -1058:
return QStringLiteral(
"CL_INVALID_PARTITION_COUNT_EXT" );
624 case -1059:
return QStringLiteral(
"CL_INVALID_PARTITION_NAME_EXT" );
625 case -1094:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_INTEL" );
626 case -1095:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_TYPE_INTEL" );
627 case -1096:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL" );
628 case -1097:
return QStringLiteral(
"CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL" );
629 case -1000:
return QStringLiteral(
"CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR" );
630 case -1098:
return QStringLiteral(
"CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL" );
631 case -1099:
return QStringLiteral(
"CL_INVALID_VA_API_MEDIA_SURFACE_INTEL" );
632 case -1100:
return QStringLiteral(
"CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL" );
633 case -1101:
return QStringLiteral(
"CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL" );
634 default:
return QStringLiteral(
"CL_UNKNOWN_ERROR" );
646 return cl::CommandQueue(
context );
651 const cl_command_queue_properties properties = 0;
653 cl_command_queue queue = clCreateCommandQueue(
context(), device(), properties,
nullptr );
655 return cl::CommandQueue( queue,
true );
662 static std::once_flag contextCreated;
663 std::call_once( contextCreated, [ = ]()
665 if (
available() && cl::Platform::getDefault()() && cl::Device::getDefault()() )
667 context = cl::Context( cl::Device::getDefault() );
689 if ( ok && version < 2.0f )
691 program.build( QStringLiteral(
"-cl-std=CL%1 -I\"%2\"" )
697 program.build( QStringLiteral(
"-I\"%1\"" )
701 catch ( cl::BuildError &e )
704 if ( build_log.isEmpty() )
705 build_log = QObject::tr(
"Build logs not available!" );
706 const QString err = QObject::tr(
"Error building OpenCL program: %1" )
709 if ( exceptionBehavior ==
Throw )
712 catch ( cl::Error &e )
714 const QString err = QObject::tr(
"Error %1 building OpenCL program in %2" )
715 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) );
@ Warning
Warning message.
@ Critical
Critical/error message.
@ Info
Information message.
@ Success
Used for reporting a successful operation.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
The QgsOpenClUtils class is responsible for common OpenCL operations such as.
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...
static void setSourcePath(const QString &value)
Set the base path to OpenCL program directory.
static QString buildLog(cl::BuildError &error)
Extract and return the build log error from error.
static void storePreferredDevice(const QString deviceId)
Store in the settings the preferred deviceId device identifier.
static QString sourcePath()
Returns the base path to OpenCL program directory.
static cl::Context context()
Context factory.
static cl::Device activeDevice()
Returns the active device.
static bool enabled()
Returns true if OpenCL is enabled in the user settings.
static bool available()
Checks whether a suitable OpenCL platform and device is available on this system and initialize the Q...
static QString deviceDescription(const cl::Device device)
Returns a formatted description for the device.
static QString activeDeviceInfo(const Info infoType=Info::Name)
Returns infoType information about the active (default) device.
static const std::vector< cl::Device > devices()
Returns a list of OpenCL devices found on this sysytem.
static void setEnabled(bool enabled)
Set the OpenCL user setting to enabled.
static QString preferredDevice()
Read from the settings the preferred device identifier.
static QString deviceInfo(const Info infoType, cl::Device device)
Returns infoType information about the device.
static QString errorText(const int errorCode)
Returns a string representation from an OpenCL errorCode.
static cl::CommandQueue commandQueue()
Create an OpenCL command queue from the default context.
static QString sourceFromPath(const QString &path)
Read an OpenCL source file from path.
static QString sourceFromBaseName(const QString &baseName)
Returns the full path to a an OpenCL source file from the baseName ('.cl' extension is automatically ...
ExceptionBehavior
The ExceptionBehavior enum define how exceptions generated by OpenCL should be treated.
@ Throw
Write errors in the message log and re-throw exceptions.
static QString deviceId(const cl::Device device)
Create a string identifier from a device.
Info
The Info enum maps to OpenCL info constants.
static QLatin1String LOGMESSAGE_TAG
OpenCL string for message logs.
static QString activePlatformVersion()
Returns the active platform OpenCL version string (e.g.
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.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)