17#include "moc_qgsopenclutils.cpp"
29#if defined(UNICODE) && !defined(_UNICODE)
41QLatin1String QgsOpenClUtils::SETTINGS_GLOBAL_ENABLED_KEY = QLatin1String(
"OpenClEnabled" );
42QLatin1String QgsOpenClUtils::SETTINGS_DEFAULT_DEVICE_KEY = QLatin1String(
"OpenClDefaultDevice" );
44bool QgsOpenClUtils::sAvailable =
false;
51 std::vector<cl::Platform> platforms;
52 cl::Platform::get( &platforms );
53 std::vector<cl::Device> existingDevices;
54 for (
const auto &p : platforms )
56 const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
58 .arg( QString::fromStdString( platver ),
59 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
61 if ( platver.find(
"OpenCL " ) != std::string::npos )
63 std::vector<cl::Device> _devices;
67 p.getDevices( CL_DEVICE_TYPE_ALL, &_devices );
69 catch ( cl::Error &e )
72 .arg( errorText( e.err() ),
73 QString::fromStdString( e.what() ),
74 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
77 if ( _devices.size() > 0 )
79 for (
unsigned long i = 0; i < _devices.size(); i++ )
82 .arg( deviceId( _devices[i] ) ),
84 existingDevices.push_back( _devices[i] );
89 return existingDevices;
92void QgsOpenClUtils::init()
94 static std::once_flag initialized;
95 std::call_once( initialized, [ = ]( )
98 QLibrary openCLLib { QStringLiteral(
"/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL" ) };
100 QLibrary openCLLib { QStringLiteral(
"OpenCL" ) };
102 openCLLib.setLoadHints( QLibrary::LoadHint::ResolveAllSymbolsHint );
103 if ( ! openCLLib.load() )
106 .arg( openCLLib.errorString() ),
117 HMODULE hModule = GetModuleHandle( _T(
"OpenCL.dll" ) );
120 TCHAR pszFileName[1024];
121 if ( GetModuleFileName( hModule, pszFileName, 1024 ) < 1024 )
128 DWORD dwLen = GetFileVersionInfoSize( pszFileName, &dwUseless );
131 LPTSTR lpVI = ( LPTSTR ) malloc( dwLen *
sizeof( TCHAR ) );
134 if ( GetFileVersionInfo( pszFileName, 0, dwLen, lpVI ) )
136 VS_FIXEDFILEINFO *lpFFI;
137 if ( VerQueryValue( lpVI, _T(
"\\" ), ( LPVOID * ) &lpFFI, ( UINT * ) &dwUseless ) )
140 .arg( lpFFI->dwProductVersionMS >> 16 )
141 .arg( lpFFI->dwProductVersionMS & 0xffff )
142 .arg( lpFFI->dwProductVersionLS >> 16 )
143 .arg( lpFFI->dwProductVersionLS & 0xffff ),
147 struct LANGANDCODEPAGE
155 if ( VerQueryValue( lpVI, _T(
"\\VarFileInfo\\Translation" ), ( LPVOID * ) &lpTranslate, ( UINT * ) &cbTranslate ) && cbTranslate >=
sizeof(
struct LANGANDCODEPAGE ) )
157 QStringList items = QStringList()
158 << QStringLiteral(
"Comments" )
159 << QStringLiteral(
"InternalName" )
160 << QStringLiteral(
"ProductName" )
161 << QStringLiteral(
"CompanyName" )
162 << QStringLiteral(
"LegalCopyright" )
163 << QStringLiteral(
"ProductVersion" )
164 << QStringLiteral(
"FileDescription" )
165 << QStringLiteral(
"LegalTrademarks" )
166 << QStringLiteral(
"PrivateBuild" )
167 << QStringLiteral(
"FileVersion" )
168 << QStringLiteral(
"OriginalFilename" )
169 << QStringLiteral(
"SpecialBuild" );
170 for (
auto d : items )
173 QString subBlock = QString( QStringLiteral(
"\\StringFileInfo\\%1%2\\%3" ) )
174 .arg( lpTranslate[0].wLanguage, 4, 16, QLatin1Char(
'0' ) )
175 .arg( lpTranslate[0].wCodePage, 4, 16, QLatin1Char(
'0' ) )
178 QgsDebugMsgLevel( QString(
"d:%1 subBlock:%2" ).arg( d ).arg( subBlock ), 2 );
180 BOOL r = VerQueryValue( lpVI,
182 subBlock.toStdWString().c_str(),
186 ( LPVOID * )&lpBuffer, ( UINT * )&dwUseless );
188 if ( r && lpBuffer && lpBuffer != INVALID_HANDLE_VALUE && dwUseless < 1023 )
193 .arg( QString::fromUtf16( (
const ushort * ) lpBuffer ) ),
195 .arg( QString::fromLocal8Bit( lpBuffer ) ),
222 catch ( cl::Error &e )
225 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
234 return *sSourcePath();
239 *sSourcePath() = value;
254 return QString::fromStdString( device.getInfo<CL_DEVICE_VENDOR>() );
256 return QString::fromStdString( device.getInfo<CL_DEVICE_PROFILE>() );
258 return QString::fromStdString( device.getInfo<CL_DEVICE_VERSION>() );
260 return device.getInfo<CL_DEVICE_IMAGE_SUPPORT>() ? QStringLiteral(
"True" ) : QStringLiteral(
"False" );
262 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>() );
264 return QString::number( device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() );
266 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() );
269 const unsigned long type( device.getInfo<CL_DEVICE_TYPE>() );
273 case CL_DEVICE_TYPE_CPU:
276 case CL_DEVICE_TYPE_GPU:
282 const QMetaEnum metaEnum = QMetaEnum::fromType<QgsOpenClUtils::HardwareType>();
283 return metaEnum.valueToKey( mappedType );
286 return QString::fromStdString( device.getInfo<CL_DEVICE_NAME>() );
289 catch ( cl::Error &e )
292 QgsDebugMsgLevel( QStringLiteral(
"Error %1 getting info for OpenCL device: %2" )
293 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
308 return cl::Device::getDefault();
314 if ( cl::Platform::getDefault()() )
316 const std::string platver = cl::Platform::getDefault().getInfo<CL_PLATFORM_VERSION>();
317 if ( platver.find(
"OpenCL " ) != std::string::npos )
319 version = QString::fromStdString( platver.substr( 7 ) ).split(
' ' ).first();
337 return QStringLiteral(
"%1|%2|%3|%4" )
345static void emitLogMessageForSEHException(
int exceptionCode )
347 QgsMessageLog::logMessage( QObject::tr(
"Unexpected exception of code %1 occurred while searching for OpenCL device. Note that the application may become unreliable and may need to be restarted." ).arg( exceptionCode ),
352bool QgsOpenClUtils::activate(
const QString &preferredDeviceId )
359 return activateInternal( preferredDeviceId );
361 __except ( EXCEPTION_EXECUTE_HANDLER )
363 emitLogMessageForSEHException( GetExceptionCode() );
367 return activateInternal( preferredDeviceId );
371bool QgsOpenClUtils::activateInternal(
const QString &preferredDeviceId )
381 std::vector<cl::Platform> platforms;
382 cl::Platform::get( &platforms );
385 bool deviceFound =
false;
386 for (
const auto &p : platforms )
390 const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
391 QgsDebugMsgLevel( QStringLiteral(
"Found OpenCL platform %1: %2" ).arg( QString::fromStdString( platver ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ), 2 );
392 if ( platver.find(
"OpenCL " ) != std::string::npos )
394 std::vector<cl::Device>
devices;
398 p.getDevices( CL_DEVICE_TYPE_ALL, &
devices );
400 if ( ! preferredDeviceId.isEmpty() )
402 for (
const auto &_dev :
devices )
404 if ( preferredDeviceId ==
deviceId( _dev ) )
417 for (
const auto &_dev :
devices )
419 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
432 for (
const auto &_dev :
devices )
434 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU )
449 catch ( cl::Error &e )
451 QgsDebugError( QStringLiteral(
"Error %1 on platform %3 searching for OpenCL device: %2" )
453 QString::fromStdString( e.what() ),
454 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
466 const cl::Platform newP = cl::Platform::setDefault( plat );
475 cl::Device::setDefault( dev );
477 .arg( QString::fromStdString( dev.getInfo<CL_DEVICE_NAME>() ) ),
484 catch ( cl::Error &e )
487 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
497 return QStringLiteral(
498 "Type: <b>%9</b><br>"
499 "Name: <b>%1</b><br>"
500 "Vendor: <b>%2</b><br>"
501 "Profile: <b>%3</b><br>"
502 "Version: <b>%4</b><br>"
503 "Image support: <b>%5</b><br>"
504 "Max image2d width: <b>%6</b><br>"
505 "Max image2d height: <b>%7</b><br>"
506 "Max mem alloc size: <b>%8</b><br>"
520 for (
const auto &dev :
devices( ) )
547 if ( file.open( QFile::ReadOnly | QFile::Text ) )
549 QTextStream in( &file );
550 source_str = in.readAll();
562 const QString path = QStringLiteral(
"%1/%2.cl" ).arg(
sourcePath(), baseName );
568 cl::BuildLogType build_logs = error.getBuildLog();
570 if ( build_logs.size() > 0 )
571 build_log = QString::fromStdString( build_logs[0].second );
579 case 0:
return QStringLiteral(
"CL_SUCCESS" );
580 case -1:
return QStringLiteral(
"CL_DEVICE_NOT_FOUND" );
581 case -2:
return QStringLiteral(
"CL_DEVICE_NOT_AVAILABLE" );
582 case -3:
return QStringLiteral(
"CL_COMPILER_NOT_AVAILABLE" );
583 case -4:
return QStringLiteral(
"CL_MEM_OBJECT_ALLOCATION_FAILURE" );
584 case -5:
return QStringLiteral(
"CL_OUT_OF_RESOURCES" );
585 case -6:
return QStringLiteral(
"CL_OUT_OF_HOST_MEMORY" );
586 case -7:
return QStringLiteral(
"CL_PROFILING_INFO_NOT_AVAILABLE" );
587 case -8:
return QStringLiteral(
"CL_MEM_COPY_OVERLAP" );
588 case -9:
return QStringLiteral(
"CL_IMAGE_FORMAT_MISMATCH" );
589 case -10:
return QStringLiteral(
"CL_IMAGE_FORMAT_NOT_SUPPORTED" );
590 case -12:
return QStringLiteral(
"CL_MAP_FAILURE" );
591 case -13:
return QStringLiteral(
"CL_MISALIGNED_SUB_BUFFER_OFFSET" );
592 case -14:
return QStringLiteral(
"CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST" );
593 case -15:
return QStringLiteral(
"CL_COMPILE_PROGRAM_FAILURE" );
594 case -16:
return QStringLiteral(
"CL_LINKER_NOT_AVAILABLE" );
595 case -17:
return QStringLiteral(
"CL_LINK_PROGRAM_FAILURE" );
596 case -18:
return QStringLiteral(
"CL_DEVICE_PARTITION_FAILED" );
597 case -19:
return QStringLiteral(
"CL_KERNEL_ARG_INFO_NOT_AVAILABLE" );
598 case -30:
return QStringLiteral(
"CL_INVALID_VALUE" );
599 case -31:
return QStringLiteral(
"CL_INVALID_DEVICE_TYPE" );
600 case -32:
return QStringLiteral(
"CL_INVALID_PLATFORM" );
601 case -33:
return QStringLiteral(
"CL_INVALID_DEVICE" );
602 case -34:
return QStringLiteral(
"CL_INVALID_CONTEXT" );
603 case -35:
return QStringLiteral(
"CL_INVALID_QUEUE_PROPERTIES" );
604 case -36:
return QStringLiteral(
"CL_INVALID_COMMAND_QUEUE" );
605 case -37:
return QStringLiteral(
"CL_INVALID_HOST_PTR" );
606 case -38:
return QStringLiteral(
"CL_INVALID_MEM_OBJECT" );
607 case -39:
return QStringLiteral(
"CL_INVALID_IMAGE_FORMAT_DESCRIPTOR" );
608 case -40:
return QStringLiteral(
"CL_INVALID_IMAGE_SIZE" );
609 case -41:
return QStringLiteral(
"CL_INVALID_SAMPLER" );
610 case -42:
return QStringLiteral(
"CL_INVALID_BINARY" );
611 case -43:
return QStringLiteral(
"CL_INVALID_BUILD_OPTIONS" );
612 case -44:
return QStringLiteral(
"CL_INVALID_PROGRAM" );
613 case -45:
return QStringLiteral(
"CL_INVALID_PROGRAM_EXECUTABLE" );
614 case -46:
return QStringLiteral(
"CL_INVALID_KERNEL_NAME" );
615 case -47:
return QStringLiteral(
"CL_INVALID_KERNEL_DEFINITION" );
616 case -48:
return QStringLiteral(
"CL_INVALID_KERNEL" );
617 case -49:
return QStringLiteral(
"CL_INVALID_ARG_INDEX" );
618 case -50:
return QStringLiteral(
"CL_INVALID_ARG_VALUE" );
619 case -51:
return QStringLiteral(
"CL_INVALID_ARG_SIZE" );
620 case -52:
return QStringLiteral(
"CL_INVALID_KERNEL_ARGS" );
621 case -53:
return QStringLiteral(
"CL_INVALID_WORK_DIMENSION" );
622 case -54:
return QStringLiteral(
"CL_INVALID_WORK_GROUP_SIZE" );
623 case -55:
return QStringLiteral(
"CL_INVALID_WORK_ITEM_SIZE" );
624 case -56:
return QStringLiteral(
"CL_INVALID_GLOBAL_OFFSET" );
625 case -57:
return QStringLiteral(
"CL_INVALID_EVENT_WAIT_LIST" );
626 case -58:
return QStringLiteral(
"CL_INVALID_EVENT" );
627 case -59:
return QStringLiteral(
"CL_INVALID_OPERATION" );
628 case -60:
return QStringLiteral(
"CL_INVALID_GL_OBJECT" );
629 case -61:
return QStringLiteral(
"CL_INVALID_BUFFER_SIZE" );
630 case -62:
return QStringLiteral(
"CL_INVALID_MIP_LEVEL" );
631 case -63:
return QStringLiteral(
"CL_INVALID_GLOBAL_WORK_SIZE" );
632 case -64:
return QStringLiteral(
"CL_INVALID_PROPERTY" );
633 case -65:
return QStringLiteral(
"CL_INVALID_IMAGE_DESCRIPTOR" );
634 case -66:
return QStringLiteral(
"CL_INVALID_COMPILER_OPTIONS" );
635 case -67:
return QStringLiteral(
"CL_INVALID_LINKER_OPTIONS" );
636 case -68:
return QStringLiteral(
"CL_INVALID_DEVICE_PARTITION_COUNT" );
637 case -69:
return QStringLiteral(
"CL_INVALID_PIPE_SIZE" );
638 case -70:
return QStringLiteral(
"CL_INVALID_DEVICE_QUEUE" );
639 case -71:
return QStringLiteral(
"CL_INVALID_SPEC_ID" );
640 case -72:
return QStringLiteral(
"CL_MAX_SIZE_RESTRICTION_EXCEEDED" );
641 case -1002:
return QStringLiteral(
"CL_INVALID_D3D10_DEVICE_KHR" );
642 case -1003:
return QStringLiteral(
"CL_INVALID_D3D10_RESOURCE_KHR" );
643 case -1004:
return QStringLiteral(
"CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR" );
644 case -1005:
return QStringLiteral(
"CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR" );
645 case -1006:
return QStringLiteral(
"CL_INVALID_D3D11_DEVICE_KHR" );
646 case -1007:
return QStringLiteral(
"CL_INVALID_D3D11_RESOURCE_KHR" );
647 case -1008:
return QStringLiteral(
"CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR" );
648 case -1009:
return QStringLiteral(
"CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR" );
649 case -1010:
return QStringLiteral(
"CL_INVALID_DX9_MEDIA_ADAPTER_KHR" );
650 case -1011:
return QStringLiteral(
"CL_INVALID_DX9_MEDIA_SURFACE_KHR" );
651 case -1012:
return QStringLiteral(
"CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR" );
652 case -1013:
return QStringLiteral(
"CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR" );
653 case -1093:
return QStringLiteral(
"CL_INVALID_EGL_OBJECT_KHR" );
654 case -1092:
return QStringLiteral(
"CL_EGL_RESOURCE_NOT_ACQUIRED_KHR" );
655 case -1001:
return QStringLiteral(
"CL_PLATFORM_NOT_FOUND_KHR" );
656 case -1057:
return QStringLiteral(
"CL_DEVICE_PARTITION_FAILED_EXT" );
657 case -1058:
return QStringLiteral(
"CL_INVALID_PARTITION_COUNT_EXT" );
658 case -1059:
return QStringLiteral(
"CL_INVALID_PARTITION_NAME_EXT" );
659 case -1094:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_INTEL" );
660 case -1095:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_TYPE_INTEL" );
661 case -1096:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL" );
662 case -1097:
return QStringLiteral(
"CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL" );
663 case -1000:
return QStringLiteral(
"CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR" );
664 case -1098:
return QStringLiteral(
"CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL" );
665 case -1099:
return QStringLiteral(
"CL_INVALID_VA_API_MEDIA_SURFACE_INTEL" );
666 case -1100:
return QStringLiteral(
"CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL" );
667 case -1101:
return QStringLiteral(
"CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL" );
668 default:
return QStringLiteral(
"CL_UNKNOWN_ERROR" );
680 return cl::CommandQueue(
context );
685 const cl_command_queue_properties properties = 0;
687 cl_command_queue queue = clCreateCommandQueue(
context(), device(), properties,
nullptr );
689 return cl::CommandQueue( queue,
true );
696 static std::once_flag contextCreated;
697 std::call_once( contextCreated, [ = ]()
699 if (
available() && cl::Platform::getDefault()() && cl::Device::getDefault()() )
701 context = cl::Context( cl::Device::getDefault() );
723 if ( ok && version < 2.0f )
725 program.build( QStringLiteral(
"-cl-std=CL%1 -I\"%2\"" )
731 program.build( QStringLiteral(
"-I\"%1\"" )
735 catch ( cl::BuildError &e )
738 if ( build_log.isEmpty() )
739 build_log = QObject::tr(
"Build logs not available!" );
740 const QString err = QObject::tr(
"Error building OpenCL program: %1" )
743 if ( exceptionBehavior ==
Throw )
746 catch ( cl::Error &e )
748 const QString err = QObject::tr(
"Error %1 building OpenCL program in %2" )
749 .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)