29#include "moc_qgsopenclutils.cpp"
31using namespace Qt::StringLiterals;
34#if defined( UNICODE ) && !defined( _UNICODE )
41#if defined( _MSC_VER )
51bool QgsOpenClUtils::sAvailable =
false;
56const std::vector<cl::Device> QgsOpenClUtils::
devices()
58 std::vector<cl::Platform> platforms;
59 cl::Platform::get( &platforms );
60 std::vector<cl::Device> existingDevices;
61 for (
const auto &p : platforms )
63 const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
66 if ( platver.find(
"OpenCL " ) != std::string::npos )
68 std::vector<cl::Device> _devices;
72 p.getDevices( CL_DEVICE_TYPE_ALL, &_devices );
74 catch ( cl::Error &e )
77 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>() ) ),
82 if ( _devices.size() > 0 )
84 for (
unsigned long i = 0; i < _devices.size(); i++ )
87 existingDevices.push_back( _devices[i] );
92 return existingDevices;
95void QgsOpenClUtils::init()
97 static std::once_flag initialized;
98 std::call_once( initialized, []() {
100 QLibrary openCLLib { u
"/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL"_s };
102 QLibrary openCLLib { u
"OpenCL"_s };
104 openCLLib.setLoadHints( QLibrary::LoadHint::ResolveAllSymbolsHint );
105 if ( !openCLLib.load() )
117 HMODULE hModule = GetModuleHandle( _T(
"OpenCL.dll" ) );
120 TCHAR pszFileName[1024];
121 if ( GetModuleFileName( hModule, pszFileName, 1024 ) < 1024 )
126 DWORD dwLen = GetFileVersionInfoSize( pszFileName, &dwUseless );
129 LPTSTR lpVI = ( LPTSTR ) malloc( dwLen *
sizeof( TCHAR ) );
132 if ( GetFileVersionInfo( pszFileName, 0, dwLen, lpVI ) )
134 VS_FIXEDFILEINFO *lpFFI;
135 if ( VerQueryValue( lpVI, _T(
"\\" ), ( LPVOID * ) &lpFFI, ( UINT * ) &dwUseless ) )
138 QObject::tr(
"OpenCL Product version: %1.%2.%3.%4" )
139 .arg( lpFFI->dwProductVersionMS >> 16 )
140 .arg( lpFFI->dwProductVersionMS & 0xffff )
141 .arg( lpFFI->dwProductVersionLS >> 16 )
142 .arg( lpFFI->dwProductVersionLS & 0xffff ),
148 struct LANGANDCODEPAGE
156 if ( VerQueryValue( lpVI, _T(
"\\VarFileInfo\\Translation" ), ( LPVOID * ) &lpTranslate, ( UINT * ) &cbTranslate ) && cbTranslate >=
sizeof(
struct LANGANDCODEPAGE ) )
158 QStringList items = QStringList()
163 << u
"LegalCopyright"_s
164 << u
"ProductVersion"_s
165 << u
"FileDescription"_s
166 << u
"LegalTrademarks"_s
169 << u
"OriginalFilename"_s
170 << u
"SpecialBuild"_s;
171 for (
auto d : items )
174 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 );
176 QgsDebugMsgLevel( QString(
"d:%1 subBlock:%2" ).arg( d ).arg( subBlock ), 2 );
178 BOOL r = VerQueryValue(
181 subBlock.toStdWString().c_str(),
185 ( LPVOID * ) &lpBuffer,
186 ( UINT * ) &dwUseless
189 if ( r && lpBuffer && lpBuffer != INVALID_HANDLE_VALUE && dwUseless < 1023 )
192 QObject::tr(
"Found OpenCL version info %1: %2" )
195 .arg( QString::fromUtf16( (
const ushort * ) lpBuffer ) ),
197 .arg( QString::fromLocal8Bit( lpBuffer ) ),
226 catch ( cl::Error &e )
235 return *sSourcePath();
240 *sSourcePath() = value;
255 return QString::fromStdString( device.getInfo<CL_DEVICE_VENDOR>() );
257 return QString::fromStdString( device.getInfo<CL_DEVICE_PROFILE>() );
259 return QString::fromStdString( device.getInfo<CL_DEVICE_VERSION>() );
261 return device.getInfo<CL_DEVICE_IMAGE_SUPPORT>() ? u
"True"_s : u
"False"_s;
263 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>() );
265 return QString::number( device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() );
267 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() );
270 const unsigned long type( device.getInfo<CL_DEVICE_TYPE>() );
274 case CL_DEVICE_TYPE_CPU:
277 case CL_DEVICE_TYPE_GPU:
283 const QMetaEnum metaEnum = QMetaEnum::fromType<QgsOpenClUtils::HardwareType>();
284 return metaEnum.valueToKey( mappedType );
287 return QString::fromStdString( device.getInfo<CL_DEVICE_NAME>() );
290 catch ( cl::Error &e )
293 QgsDebugMsgLevel( u
"Error %1 getting info for OpenCL device: %2"_s.arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ), 4 );
307 return cl::Device::getDefault();
313 if ( cl::Platform::getDefault()() )
315 const std::string platver = cl::Platform::getDefault().getInfo<CL_PLATFORM_VERSION>();
316 if ( platver.find(
"OpenCL " ) != std::string::npos )
318 version = QString::fromStdString( platver.substr( 7 ) ).split(
' ' ).first();
336 return u
"%1|%2|%3|%4"_s
340#if defined( _MSC_VER )
341static void emitLogMessageForSEHException(
int exceptionCode )
344 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 ),
351bool QgsOpenClUtils::activate(
const QString &preferredDeviceId )
353#if defined( _MSC_VER )
358 return activateInternal( preferredDeviceId );
360 __except ( EXCEPTION_EXECUTE_HANDLER )
362 emitLogMessageForSEHException( GetExceptionCode() );
366 return activateInternal( preferredDeviceId );
370bool QgsOpenClUtils::activateInternal(
const QString &preferredDeviceId )
380 std::vector<cl::Platform> platforms;
381 cl::Platform::get( &platforms );
384 bool deviceFound =
false;
385 for (
const auto &p : platforms )
389 const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
390 QgsDebugMsgLevel( u
"Found OpenCL platform %1: %2"_s.arg( QString::fromStdString( platver ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ), 2 );
391 if ( platver.find(
"OpenCL " ) != std::string::npos )
393 std::vector<cl::Device>
devices;
397 p.getDevices( CL_DEVICE_TYPE_ALL, &
devices );
399 if ( !preferredDeviceId.isEmpty() )
401 for (
const auto &_dev :
devices )
403 if ( preferredDeviceId ==
deviceId( _dev ) )
416 for (
const auto &_dev :
devices )
418 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
431 for (
const auto &_dev :
devices )
433 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU )
448 catch ( cl::Error &e )
451 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>() ) )
463 const cl::Platform newP = cl::Platform::setDefault( plat );
471 cl::Device::setDefault( dev );
478 catch ( cl::Error &e )
489 return QStringLiteral(
490 "Type: <b>%9</b><br>"
491 "Name: <b>%1</b><br>"
492 "Vendor: <b>%2</b><br>"
493 "Profile: <b>%3</b><br>"
494 "Version: <b>%4</b><br>"
495 "Image support: <b>%5</b><br>"
496 "Max image2d width: <b>%6</b><br>"
497 "Max image2d height: <b>%7</b><br>"
498 "Max mem alloc size: <b>%8</b><br>"
515 for (
const auto &dev :
devices() )
541 if ( file.open( QFile::ReadOnly | QFile::Text ) )
543 QTextStream in( &file );
544 source_str = in.readAll();
556 const QString path = u
"%1/%2.cl"_s.arg(
sourcePath(), baseName );
562 cl::BuildLogType build_logs = error.getBuildLog();
564 if ( build_logs.size() > 0 )
565 build_log = QString::fromStdString( build_logs[0].second );
574 return u
"CL_SUCCESS"_s;
576 return u
"CL_DEVICE_NOT_FOUND"_s;
578 return u
"CL_DEVICE_NOT_AVAILABLE"_s;
580 return u
"CL_COMPILER_NOT_AVAILABLE"_s;
582 return u
"CL_MEM_OBJECT_ALLOCATION_FAILURE"_s;
584 return u
"CL_OUT_OF_RESOURCES"_s;
586 return u
"CL_OUT_OF_HOST_MEMORY"_s;
588 return u
"CL_PROFILING_INFO_NOT_AVAILABLE"_s;
590 return u
"CL_MEM_COPY_OVERLAP"_s;
592 return u
"CL_IMAGE_FORMAT_MISMATCH"_s;
594 return u
"CL_IMAGE_FORMAT_NOT_SUPPORTED"_s;
596 return u
"CL_MAP_FAILURE"_s;
598 return u
"CL_MISALIGNED_SUB_BUFFER_OFFSET"_s;
600 return u
"CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST"_s;
602 return u
"CL_COMPILE_PROGRAM_FAILURE"_s;
604 return u
"CL_LINKER_NOT_AVAILABLE"_s;
606 return u
"CL_LINK_PROGRAM_FAILURE"_s;
608 return u
"CL_DEVICE_PARTITION_FAILED"_s;
610 return u
"CL_KERNEL_ARG_INFO_NOT_AVAILABLE"_s;
612 return u
"CL_INVALID_VALUE"_s;
614 return u
"CL_INVALID_DEVICE_TYPE"_s;
616 return u
"CL_INVALID_PLATFORM"_s;
618 return u
"CL_INVALID_DEVICE"_s;
620 return u
"CL_INVALID_CONTEXT"_s;
622 return u
"CL_INVALID_QUEUE_PROPERTIES"_s;
624 return u
"CL_INVALID_COMMAND_QUEUE"_s;
626 return u
"CL_INVALID_HOST_PTR"_s;
628 return u
"CL_INVALID_MEM_OBJECT"_s;
630 return u
"CL_INVALID_IMAGE_FORMAT_DESCRIPTOR"_s;
632 return u
"CL_INVALID_IMAGE_SIZE"_s;
634 return u
"CL_INVALID_SAMPLER"_s;
636 return u
"CL_INVALID_BINARY"_s;
638 return u
"CL_INVALID_BUILD_OPTIONS"_s;
640 return u
"CL_INVALID_PROGRAM"_s;
642 return u
"CL_INVALID_PROGRAM_EXECUTABLE"_s;
644 return u
"CL_INVALID_KERNEL_NAME"_s;
646 return u
"CL_INVALID_KERNEL_DEFINITION"_s;
648 return u
"CL_INVALID_KERNEL"_s;
650 return u
"CL_INVALID_ARG_INDEX"_s;
652 return u
"CL_INVALID_ARG_VALUE"_s;
654 return u
"CL_INVALID_ARG_SIZE"_s;
656 return u
"CL_INVALID_KERNEL_ARGS"_s;
658 return u
"CL_INVALID_WORK_DIMENSION"_s;
660 return u
"CL_INVALID_WORK_GROUP_SIZE"_s;
662 return u
"CL_INVALID_WORK_ITEM_SIZE"_s;
664 return u
"CL_INVALID_GLOBAL_OFFSET"_s;
666 return u
"CL_INVALID_EVENT_WAIT_LIST"_s;
668 return u
"CL_INVALID_EVENT"_s;
670 return u
"CL_INVALID_OPERATION"_s;
672 return u
"CL_INVALID_GL_OBJECT"_s;
674 return u
"CL_INVALID_BUFFER_SIZE"_s;
676 return u
"CL_INVALID_MIP_LEVEL"_s;
678 return u
"CL_INVALID_GLOBAL_WORK_SIZE"_s;
680 return u
"CL_INVALID_PROPERTY"_s;
682 return u
"CL_INVALID_IMAGE_DESCRIPTOR"_s;
684 return u
"CL_INVALID_COMPILER_OPTIONS"_s;
686 return u
"CL_INVALID_LINKER_OPTIONS"_s;
688 return u
"CL_INVALID_DEVICE_PARTITION_COUNT"_s;
690 return u
"CL_INVALID_PIPE_SIZE"_s;
692 return u
"CL_INVALID_DEVICE_QUEUE"_s;
694 return u
"CL_INVALID_SPEC_ID"_s;
696 return u
"CL_MAX_SIZE_RESTRICTION_EXCEEDED"_s;
698 return u
"CL_INVALID_D3D10_DEVICE_KHR"_s;
700 return u
"CL_INVALID_D3D10_RESOURCE_KHR"_s;
702 return u
"CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR"_s;
704 return u
"CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR"_s;
706 return u
"CL_INVALID_D3D11_DEVICE_KHR"_s;
708 return u
"CL_INVALID_D3D11_RESOURCE_KHR"_s;
710 return u
"CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR"_s;
712 return u
"CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR"_s;
714 return u
"CL_INVALID_DX9_MEDIA_ADAPTER_KHR"_s;
716 return u
"CL_INVALID_DX9_MEDIA_SURFACE_KHR"_s;
718 return u
"CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR"_s;
720 return u
"CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR"_s;
722 return u
"CL_INVALID_EGL_OBJECT_KHR"_s;
724 return u
"CL_EGL_RESOURCE_NOT_ACQUIRED_KHR"_s;
726 return u
"CL_PLATFORM_NOT_FOUND_KHR"_s;
728 return u
"CL_DEVICE_PARTITION_FAILED_EXT"_s;
730 return u
"CL_INVALID_PARTITION_COUNT_EXT"_s;
732 return u
"CL_INVALID_PARTITION_NAME_EXT"_s;
734 return u
"CL_INVALID_ACCELERATOR_INTEL"_s;
736 return u
"CL_INVALID_ACCELERATOR_TYPE_INTEL"_s;
738 return u
"CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL"_s;
740 return u
"CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL"_s;
742 return u
"CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR"_s;
744 return u
"CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL"_s;
746 return u
"CL_INVALID_VA_API_MEDIA_SURFACE_INTEL"_s;
748 return u
"CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL"_s;
750 return u
"CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL"_s;
752 return u
"CL_UNKNOWN_ERROR"_s;
764 return cl::CommandQueue(
context );
769 const cl_command_queue_properties properties = 0;
771 cl_command_queue queue = clCreateCommandQueue(
context(), device(), properties,
nullptr );
773 return cl::CommandQueue( queue,
true );
780 static std::once_flag contextCreated;
781 std::call_once( contextCreated, []() {
782 if (
available() && cl::Platform::getDefault()() && cl::Device::getDefault()() )
784 context = cl::Context( cl::Device::getDefault() );
806 if ( ok && version < 2.0f )
812 program.build( u
"-I\"%1\""_s.arg(
sourcePath() ).toStdString().c_str() );
815 catch ( cl::BuildError &e )
818 if ( build_log.isEmpty() )
819 build_log = QObject::tr(
"Build logs not available!" );
820 const QString err = QObject::tr(
"Error building OpenCL program: %1" ).arg( build_log );
822 if ( exceptionBehavior ==
Throw )
825 catch ( cl::Error &e )
827 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 const QgsSettingsEntryBool * settingsOpenClEnabled
static const QgsSettingsEntryString * settingsOpenClDefaultDevice
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.
A boolean settings entry.
static QgsSettingsTreeNode * sTreeCore
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)