28#include "moc_qgsopenclutils.cpp"
30using namespace Qt::StringLiterals;
33#if defined( UNICODE ) && !defined( _UNICODE )
40#if defined( _MSC_VER )
45QLatin1String QgsOpenClUtils::SETTINGS_GLOBAL_ENABLED_KEY =
"OpenClEnabled"_L1;
46QLatin1String QgsOpenClUtils::SETTINGS_DEFAULT_DEVICE_KEY =
"OpenClDefaultDevice"_L1;
48bool QgsOpenClUtils::sAvailable =
false;
53const std::vector<cl::Device> QgsOpenClUtils::
devices()
55 std::vector<cl::Platform> platforms;
56 cl::Platform::get( &platforms );
57 std::vector<cl::Device> existingDevices;
58 for (
const auto &p : platforms )
60 const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
63 if ( platver.find(
"OpenCL " ) != std::string::npos )
65 std::vector<cl::Device> _devices;
69 p.getDevices( CL_DEVICE_TYPE_ALL, &_devices );
71 catch ( cl::Error &e )
74 QObject::tr(
"Error %1 on platform %3 searching for OpenCL device: %2" ).arg(
errorText( e.err() ), QString::fromStdString( e.what() ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
79 if ( _devices.size() > 0 )
81 for (
unsigned long i = 0; i < _devices.size(); i++ )
84 existingDevices.push_back( _devices[i] );
89 return existingDevices;
92void QgsOpenClUtils::init()
94 static std::once_flag initialized;
95 std::call_once( initialized, []() {
97 QLibrary openCLLib { u
"/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL"_s };
99 QLibrary openCLLib { u
"OpenCL"_s };
101 openCLLib.setLoadHints( QLibrary::LoadHint::ResolveAllSymbolsHint );
102 if ( !openCLLib.load() )
114 HMODULE hModule = GetModuleHandle( _T(
"OpenCL.dll" ) );
117 TCHAR pszFileName[1024];
118 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 QObject::tr(
"OpenCL Product version: %1.%2.%3.%4" )
136 .arg( lpFFI->dwProductVersionMS >> 16 )
137 .arg( lpFFI->dwProductVersionMS & 0xffff )
138 .arg( lpFFI->dwProductVersionLS >> 16 )
139 .arg( lpFFI->dwProductVersionLS & 0xffff ),
145 struct LANGANDCODEPAGE
153 if ( VerQueryValue( lpVI, _T(
"\\VarFileInfo\\Translation" ), ( LPVOID * ) &lpTranslate, ( UINT * ) &cbTranslate ) && cbTranslate >=
sizeof(
struct LANGANDCODEPAGE ) )
155 QStringList items = QStringList()
160 << u
"LegalCopyright"_s
161 << u
"ProductVersion"_s
162 << u
"FileDescription"_s
163 << u
"LegalTrademarks"_s
166 << u
"OriginalFilename"_s
167 << u
"SpecialBuild"_s;
168 for (
auto d : items )
171 QString subBlock = QString( u
"\\StringFileInfo\\%1%2\\%3"_s ).arg( lpTranslate[0].wLanguage, 4, 16,
'0'_L1 ).arg( lpTranslate[0].wCodePage, 4, 16,
'0'_L1 ).arg( d );
173 QgsDebugMsgLevel( QString(
"d:%1 subBlock:%2" ).arg( d ).arg( subBlock ), 2 );
175 BOOL r = VerQueryValue(
178 subBlock.toStdWString().c_str(),
182 ( LPVOID * ) &lpBuffer,
183 ( UINT * ) &dwUseless
186 if ( r && lpBuffer && lpBuffer != INVALID_HANDLE_VALUE && dwUseless < 1023 )
189 QObject::tr(
"Found OpenCL version info %1: %2" )
192 .arg( QString::fromUtf16( (
const ushort * ) lpBuffer ) ),
194 .arg( QString::fromLocal8Bit( lpBuffer ) ),
223 catch ( cl::Error &e )
232 return *sSourcePath();
237 *sSourcePath() = value;
252 return QString::fromStdString( device.getInfo<CL_DEVICE_VENDOR>() );
254 return QString::fromStdString( device.getInfo<CL_DEVICE_PROFILE>() );
256 return QString::fromStdString( device.getInfo<CL_DEVICE_VERSION>() );
258 return device.getInfo<CL_DEVICE_IMAGE_SUPPORT>() ? u
"True"_s : u
"False"_s;
260 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>() );
262 return QString::number( device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() );
264 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() );
267 const unsigned long type( device.getInfo<CL_DEVICE_TYPE>() );
271 case CL_DEVICE_TYPE_CPU:
274 case CL_DEVICE_TYPE_GPU:
280 const QMetaEnum metaEnum = QMetaEnum::fromType<QgsOpenClUtils::HardwareType>();
281 return metaEnum.valueToKey( mappedType );
284 return QString::fromStdString( device.getInfo<CL_DEVICE_NAME>() );
287 catch ( cl::Error &e )
290 QgsDebugMsgLevel( u
"Error %1 getting info for OpenCL device: %2"_s.arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ), 4 );
304 return cl::Device::getDefault();
310 if ( cl::Platform::getDefault()() )
312 const std::string platver = cl::Platform::getDefault().getInfo<CL_PLATFORM_VERSION>();
313 if ( platver.find(
"OpenCL " ) != std::string::npos )
315 version = QString::fromStdString( platver.substr( 7 ) ).split(
' ' ).first();
333 return u
"%1|%2|%3|%4"_s
337#if defined( _MSC_VER )
338static void emitLogMessageForSEHException(
int exceptionCode )
341 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 ),
348bool QgsOpenClUtils::activate(
const QString &preferredDeviceId )
350#if defined( _MSC_VER )
355 return activateInternal( preferredDeviceId );
357 __except ( EXCEPTION_EXECUTE_HANDLER )
359 emitLogMessageForSEHException( GetExceptionCode() );
363 return activateInternal( preferredDeviceId );
367bool QgsOpenClUtils::activateInternal(
const QString &preferredDeviceId )
377 std::vector<cl::Platform> platforms;
378 cl::Platform::get( &platforms );
381 bool deviceFound =
false;
382 for (
const auto &p : platforms )
386 const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
387 QgsDebugMsgLevel( u
"Found OpenCL platform %1: %2"_s.arg( QString::fromStdString( platver ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ), 2 );
388 if ( platver.find(
"OpenCL " ) != std::string::npos )
390 std::vector<cl::Device>
devices;
394 p.getDevices( CL_DEVICE_TYPE_ALL, &
devices );
396 if ( !preferredDeviceId.isEmpty() )
398 for (
const auto &_dev :
devices )
400 if ( preferredDeviceId ==
deviceId( _dev ) )
413 for (
const auto &_dev :
devices )
415 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
428 for (
const auto &_dev :
devices )
430 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU )
445 catch ( cl::Error &e )
448 u
"Error %1 on platform %3 searching for OpenCL device: %2"_s.arg(
errorText( e.err() ), QString::fromStdString( e.what() ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) )
460 const cl::Platform newP = cl::Platform::setDefault( plat );
468 cl::Device::setDefault( dev );
475 catch ( cl::Error &e )
486 return QStringLiteral(
487 "Type: <b>%9</b><br>"
488 "Name: <b>%1</b><br>"
489 "Vendor: <b>%2</b><br>"
490 "Profile: <b>%3</b><br>"
491 "Version: <b>%4</b><br>"
492 "Image support: <b>%5</b><br>"
493 "Max image2d width: <b>%6</b><br>"
494 "Max image2d height: <b>%7</b><br>"
495 "Max mem alloc size: <b>%8</b><br>"
512 for (
const auto &dev :
devices() )
538 if ( file.open( QFile::ReadOnly | QFile::Text ) )
540 QTextStream in( &file );
541 source_str = in.readAll();
553 const QString path = u
"%1/%2.cl"_s.arg(
sourcePath(), baseName );
559 cl::BuildLogType build_logs = error.getBuildLog();
561 if ( build_logs.size() > 0 )
562 build_log = QString::fromStdString( build_logs[0].second );
571 return u
"CL_SUCCESS"_s;
573 return u
"CL_DEVICE_NOT_FOUND"_s;
575 return u
"CL_DEVICE_NOT_AVAILABLE"_s;
577 return u
"CL_COMPILER_NOT_AVAILABLE"_s;
579 return u
"CL_MEM_OBJECT_ALLOCATION_FAILURE"_s;
581 return u
"CL_OUT_OF_RESOURCES"_s;
583 return u
"CL_OUT_OF_HOST_MEMORY"_s;
585 return u
"CL_PROFILING_INFO_NOT_AVAILABLE"_s;
587 return u
"CL_MEM_COPY_OVERLAP"_s;
589 return u
"CL_IMAGE_FORMAT_MISMATCH"_s;
591 return u
"CL_IMAGE_FORMAT_NOT_SUPPORTED"_s;
593 return u
"CL_MAP_FAILURE"_s;
595 return u
"CL_MISALIGNED_SUB_BUFFER_OFFSET"_s;
597 return u
"CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST"_s;
599 return u
"CL_COMPILE_PROGRAM_FAILURE"_s;
601 return u
"CL_LINKER_NOT_AVAILABLE"_s;
603 return u
"CL_LINK_PROGRAM_FAILURE"_s;
605 return u
"CL_DEVICE_PARTITION_FAILED"_s;
607 return u
"CL_KERNEL_ARG_INFO_NOT_AVAILABLE"_s;
609 return u
"CL_INVALID_VALUE"_s;
611 return u
"CL_INVALID_DEVICE_TYPE"_s;
613 return u
"CL_INVALID_PLATFORM"_s;
615 return u
"CL_INVALID_DEVICE"_s;
617 return u
"CL_INVALID_CONTEXT"_s;
619 return u
"CL_INVALID_QUEUE_PROPERTIES"_s;
621 return u
"CL_INVALID_COMMAND_QUEUE"_s;
623 return u
"CL_INVALID_HOST_PTR"_s;
625 return u
"CL_INVALID_MEM_OBJECT"_s;
627 return u
"CL_INVALID_IMAGE_FORMAT_DESCRIPTOR"_s;
629 return u
"CL_INVALID_IMAGE_SIZE"_s;
631 return u
"CL_INVALID_SAMPLER"_s;
633 return u
"CL_INVALID_BINARY"_s;
635 return u
"CL_INVALID_BUILD_OPTIONS"_s;
637 return u
"CL_INVALID_PROGRAM"_s;
639 return u
"CL_INVALID_PROGRAM_EXECUTABLE"_s;
641 return u
"CL_INVALID_KERNEL_NAME"_s;
643 return u
"CL_INVALID_KERNEL_DEFINITION"_s;
645 return u
"CL_INVALID_KERNEL"_s;
647 return u
"CL_INVALID_ARG_INDEX"_s;
649 return u
"CL_INVALID_ARG_VALUE"_s;
651 return u
"CL_INVALID_ARG_SIZE"_s;
653 return u
"CL_INVALID_KERNEL_ARGS"_s;
655 return u
"CL_INVALID_WORK_DIMENSION"_s;
657 return u
"CL_INVALID_WORK_GROUP_SIZE"_s;
659 return u
"CL_INVALID_WORK_ITEM_SIZE"_s;
661 return u
"CL_INVALID_GLOBAL_OFFSET"_s;
663 return u
"CL_INVALID_EVENT_WAIT_LIST"_s;
665 return u
"CL_INVALID_EVENT"_s;
667 return u
"CL_INVALID_OPERATION"_s;
669 return u
"CL_INVALID_GL_OBJECT"_s;
671 return u
"CL_INVALID_BUFFER_SIZE"_s;
673 return u
"CL_INVALID_MIP_LEVEL"_s;
675 return u
"CL_INVALID_GLOBAL_WORK_SIZE"_s;
677 return u
"CL_INVALID_PROPERTY"_s;
679 return u
"CL_INVALID_IMAGE_DESCRIPTOR"_s;
681 return u
"CL_INVALID_COMPILER_OPTIONS"_s;
683 return u
"CL_INVALID_LINKER_OPTIONS"_s;
685 return u
"CL_INVALID_DEVICE_PARTITION_COUNT"_s;
687 return u
"CL_INVALID_PIPE_SIZE"_s;
689 return u
"CL_INVALID_DEVICE_QUEUE"_s;
691 return u
"CL_INVALID_SPEC_ID"_s;
693 return u
"CL_MAX_SIZE_RESTRICTION_EXCEEDED"_s;
695 return u
"CL_INVALID_D3D10_DEVICE_KHR"_s;
697 return u
"CL_INVALID_D3D10_RESOURCE_KHR"_s;
699 return u
"CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR"_s;
701 return u
"CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR"_s;
703 return u
"CL_INVALID_D3D11_DEVICE_KHR"_s;
705 return u
"CL_INVALID_D3D11_RESOURCE_KHR"_s;
707 return u
"CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR"_s;
709 return u
"CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR"_s;
711 return u
"CL_INVALID_DX9_MEDIA_ADAPTER_KHR"_s;
713 return u
"CL_INVALID_DX9_MEDIA_SURFACE_KHR"_s;
715 return u
"CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR"_s;
717 return u
"CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR"_s;
719 return u
"CL_INVALID_EGL_OBJECT_KHR"_s;
721 return u
"CL_EGL_RESOURCE_NOT_ACQUIRED_KHR"_s;
723 return u
"CL_PLATFORM_NOT_FOUND_KHR"_s;
725 return u
"CL_DEVICE_PARTITION_FAILED_EXT"_s;
727 return u
"CL_INVALID_PARTITION_COUNT_EXT"_s;
729 return u
"CL_INVALID_PARTITION_NAME_EXT"_s;
731 return u
"CL_INVALID_ACCELERATOR_INTEL"_s;
733 return u
"CL_INVALID_ACCELERATOR_TYPE_INTEL"_s;
735 return u
"CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL"_s;
737 return u
"CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL"_s;
739 return u
"CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR"_s;
741 return u
"CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL"_s;
743 return u
"CL_INVALID_VA_API_MEDIA_SURFACE_INTEL"_s;
745 return u
"CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL"_s;
747 return u
"CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL"_s;
749 return u
"CL_UNKNOWN_ERROR"_s;
761 return cl::CommandQueue(
context );
766 const cl_command_queue_properties properties = 0;
768 cl_command_queue queue = clCreateCommandQueue(
context(), device(), properties,
nullptr );
770 return cl::CommandQueue( queue,
true );
777 static std::once_flag contextCreated;
778 std::call_once( contextCreated, []() {
779 if (
available() && cl::Platform::getDefault()() && cl::Device::getDefault()() )
781 context = cl::Context( cl::Device::getDefault() );
803 if ( ok && version < 2.0f )
809 program.build( u
"-I\"%1\""_s.arg(
sourcePath() ).toStdString().c_str() );
812 catch ( cl::BuildError &e )
815 if ( build_log.isEmpty() )
816 build_log = QObject::tr(
"Build logs not available!" );
817 const QString err = QObject::tr(
"Error building OpenCL program: %1" ).arg( build_log );
819 if ( exceptionBehavior ==
Throw )
822 catch ( cl::Error &e )
824 const QString err = QObject::tr(
"Error %1 building OpenCL program in %2" ).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, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
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.
Stores settings for use within QGIS.
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)