23 #include <QTextStream> 27 QLatin1String QgsOpenClUtils::SETTINGS_GLOBAL_ENABLED_KEY = QLatin1Literal(
"OpenClEnabled" );
28 QLatin1String QgsOpenClUtils::SETTINGS_DEFAULT_DEVICE_KEY = QLatin1Literal(
"OpenClDefaultDevice" );
30 bool QgsOpenClUtils::sAvailable =
false;
31 QString QgsOpenClUtils::sSourcePath = QString();
36 std::vector<cl::Platform> platforms;
37 cl::Platform::get( &platforms );
38 std::vector<cl::Device> existingDevices;
39 for (
auto &p : platforms )
41 std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
42 QgsDebugMsg( QStringLiteral(
"Found OpenCL platform %1: %2" ).arg( QString::fromStdString( platver ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
43 if ( platver.find(
"OpenCL " ) != std::string::npos )
45 std::vector<cl::Device> _devices;
49 p.getDevices( CL_DEVICE_TYPE_ALL, &_devices );
51 catch ( cl::Error &e )
53 QgsDebugMsgLevel( QStringLiteral(
"Error %1 on platform %3 searching for OpenCL device: %2" )
55 QString::fromStdString( e.what() ),
56 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ), 2 );
58 if ( _devices.size() > 0 )
60 for (
unsigned long i = 0; i < _devices.size(); i++ )
62 existingDevices.push_back( _devices[i] );
67 return existingDevices;
70 void QgsOpenClUtils::init()
72 static std::once_flag initialized;
73 std::call_once( initialized, [ = ]( )
75 QLibrary openCLLib{ QStringLiteral(
"OpenCL" ) };
76 openCLLib.setLoadHints( QLibrary::LoadHint::ResolveAllSymbolsHint );
77 if ( ! openCLLib.load() )
80 .arg( openCLLib.errorString() ),
88 catch ( cl::Error &e )
91 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
120 return QString::fromStdString( device.getInfo<CL_DEVICE_VENDOR>() );
122 return QString::fromStdString( device.getInfo<CL_DEVICE_PROFILE>() );
124 return QString::fromStdString( device.getInfo<CL_DEVICE_VERSION>() );
125 case Info::ImageSupport:
126 return device.getInfo<CL_DEVICE_IMAGE_SUPPORT>() ? QStringLiteral(
"True" ) : QStringLiteral(
"False" );
127 case Info::Image2dMaxHeight:
128 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>() );
129 case Info::MaxMemAllocSize:
130 return QString::number( device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() );
131 case Info::Image2dMaxWidth:
132 return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() );
135 unsigned long type( device.getInfo<CL_DEVICE_TYPE>() );
139 case CL_DEVICE_TYPE_CPU:
140 mappedType = QgsOpenClUtils::HardwareType::CPU;
142 case CL_DEVICE_TYPE_GPU:
143 mappedType = QgsOpenClUtils::HardwareType::GPU;
146 mappedType = QgsOpenClUtils::HardwareType::Other;
148 QMetaEnum metaEnum = QMetaEnum::fromType<QgsOpenClUtils::HardwareType>();
149 return metaEnum.valueToKey( mappedType );
152 return QString::fromStdString( device.getInfo<CL_DEVICE_NAME>() );
155 catch ( cl::Error &e )
158 QgsDebugMsgLevel( QStringLiteral(
"Error %1 getting info for OpenCL device: %2" )
159 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
169 return QgsSettings().
value( SETTINGS_GLOBAL_ENABLED_KEY,
false, QgsSettings::Section::Core ).toBool();
174 return cl::Device::getDefault();
180 if ( cl::Platform::getDefault()() )
182 std::string platver = cl::Platform::getDefault().getInfo<CL_PLATFORM_VERSION>();
183 if ( platver.find(
"OpenCL " ) != std::string::npos )
185 version = QString::fromStdString( platver.substr( 7 ) ).split(
' ' ).first();
193 QgsSettings().
setValue( SETTINGS_DEFAULT_DEVICE_KEY, deviceId, QgsSettings::Section::Core );
198 return QgsSettings().
value( SETTINGS_DEFAULT_DEVICE_KEY, QString( ), QgsSettings::Section::Core ).toString();
203 return QStringLiteral(
"%1|%2|%3|%4" )
204 .arg(
deviceInfo( QgsOpenClUtils::Info::Name, device ) )
205 .arg(
deviceInfo( QgsOpenClUtils::Info::Vendor, device ) )
206 .arg(
deviceInfo( QgsOpenClUtils::Info::Version, device ) )
207 .arg(
deviceInfo( QgsOpenClUtils::Info::Type, device ) );
210 bool QgsOpenClUtils::activate(
const QString &preferredDeviceId )
219 std::vector<cl::Platform> platforms;
220 cl::Platform::get( &platforms );
223 bool deviceFound =
false;
224 for (
auto &p : platforms )
228 std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
229 QgsDebugMsg( QStringLiteral(
"Found OpenCL platform %1: %2" ).arg( QString::fromStdString( platver ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
230 if ( platver.find(
"OpenCL " ) != std::string::npos )
232 std::vector<cl::Device>
devices;
236 p.getDevices( CL_DEVICE_TYPE_ALL, &devices );
238 if ( ! preferredDeviceId.isEmpty() )
240 for (
const auto &_dev : devices )
242 if ( preferredDeviceId ==
deviceId( _dev ) )
255 for (
const auto &_dev : devices )
257 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
270 for (
const auto &_dev : devices )
272 if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU )
287 catch ( cl::Error &e )
289 QgsDebugMsg( QStringLiteral(
"Error %1 on platform %3 searching for OpenCL device: %2" )
291 QString::fromStdString( e.what() ),
292 QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
304 cl::Platform newP = cl::Platform::setDefault( plat );
313 cl::Device::setDefault( dev );
315 .arg( QString::fromStdString( dev.getInfo<CL_DEVICE_NAME>() ) ),
322 catch ( cl::Error &e )
325 .arg(
errorText( e.err() ), QString::fromStdString( e.what() ) ),
334 return QStringLiteral(
335 "Type: <b>%9</b><br>" 336 "Name: <b>%1</b><br>" 337 "Vendor: <b>%2</b><br>" 338 "Profile: <b>%3</b><br>" 339 "Version: <b>%4</b><br>" 340 "Image support: <b>%5</b><br>" 341 "Max image2d width: <b>%6</b><br>" 342 "Max image2d height: <b>%7</b><br>" 343 "Max mem alloc size: <b>%8</b><br>" 357 for (
const auto &dev :
devices( ) )
373 QgsSettings().
setValue( SETTINGS_GLOBAL_ENABLED_KEY, enabled, QgsSettings::Section::Core );
384 if ( file.open( QFile::ReadOnly | QFile::Text ) )
386 QTextStream in( &file );
387 source_str = in.readAll();
399 QString path = QStringLiteral(
"%1/%2.cl" ).arg(
sourcePath(), baseName );
405 cl::BuildLogType build_logs = error.getBuildLog();
407 if ( build_logs.size() > 0 )
408 build_log = QString::fromStdString( build_logs[0].second );
416 case 0:
return QStringLiteral(
"CL_SUCCESS" );
417 case -1:
return QStringLiteral(
"CL_DEVICE_NOT_FOUND" );
418 case -2:
return QStringLiteral(
"CL_DEVICE_NOT_AVAILABLE" );
419 case -3:
return QStringLiteral(
"CL_COMPILER_NOT_AVAILABLE" );
420 case -4:
return QStringLiteral(
"CL_MEM_OBJECT_ALLOCATION_FAILURE" );
421 case -5:
return QStringLiteral(
"CL_OUT_OF_RESOURCES" );
422 case -6:
return QStringLiteral(
"CL_OUT_OF_HOST_MEMORY" );
423 case -7:
return QStringLiteral(
"CL_PROFILING_INFO_NOT_AVAILABLE" );
424 case -8:
return QStringLiteral(
"CL_MEM_COPY_OVERLAP" );
425 case -9:
return QStringLiteral(
"CL_IMAGE_FORMAT_MISMATCH" );
426 case -10:
return QStringLiteral(
"CL_IMAGE_FORMAT_NOT_SUPPORTED" );
427 case -12:
return QStringLiteral(
"CL_MAP_FAILURE" );
428 case -13:
return QStringLiteral(
"CL_MISALIGNED_SUB_BUFFER_OFFSET" );
429 case -14:
return QStringLiteral(
"CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST" );
430 case -15:
return QStringLiteral(
"CL_COMPILE_PROGRAM_FAILURE" );
431 case -16:
return QStringLiteral(
"CL_LINKER_NOT_AVAILABLE" );
432 case -17:
return QStringLiteral(
"CL_LINK_PROGRAM_FAILURE" );
433 case -18:
return QStringLiteral(
"CL_DEVICE_PARTITION_FAILED" );
434 case -19:
return QStringLiteral(
"CL_KERNEL_ARG_INFO_NOT_AVAILABLE" );
435 case -30:
return QStringLiteral(
"CL_INVALID_VALUE" );
436 case -31:
return QStringLiteral(
"CL_INVALID_DEVICE_TYPE" );
437 case -32:
return QStringLiteral(
"CL_INVALID_PLATFORM" );
438 case -33:
return QStringLiteral(
"CL_INVALID_DEVICE" );
439 case -34:
return QStringLiteral(
"CL_INVALID_CONTEXT" );
440 case -35:
return QStringLiteral(
"CL_INVALID_QUEUE_PROPERTIES" );
441 case -36:
return QStringLiteral(
"CL_INVALID_COMMAND_QUEUE" );
442 case -37:
return QStringLiteral(
"CL_INVALID_HOST_PTR" );
443 case -38:
return QStringLiteral(
"CL_INVALID_MEM_OBJECT" );
444 case -39:
return QStringLiteral(
"CL_INVALID_IMAGE_FORMAT_DESCRIPTOR" );
445 case -40:
return QStringLiteral(
"CL_INVALID_IMAGE_SIZE" );
446 case -41:
return QStringLiteral(
"CL_INVALID_SAMPLER" );
447 case -42:
return QStringLiteral(
"CL_INVALID_BINARY" );
448 case -43:
return QStringLiteral(
"CL_INVALID_BUILD_OPTIONS" );
449 case -44:
return QStringLiteral(
"CL_INVALID_PROGRAM" );
450 case -45:
return QStringLiteral(
"CL_INVALID_PROGRAM_EXECUTABLE" );
451 case -46:
return QStringLiteral(
"CL_INVALID_KERNEL_NAME" );
452 case -47:
return QStringLiteral(
"CL_INVALID_KERNEL_DEFINITION" );
453 case -48:
return QStringLiteral(
"CL_INVALID_KERNEL" );
454 case -49:
return QStringLiteral(
"CL_INVALID_ARG_INDEX" );
455 case -50:
return QStringLiteral(
"CL_INVALID_ARG_VALUE" );
456 case -51:
return QStringLiteral(
"CL_INVALID_ARG_SIZE" );
457 case -52:
return QStringLiteral(
"CL_INVALID_KERNEL_ARGS" );
458 case -53:
return QStringLiteral(
"CL_INVALID_WORK_DIMENSION" );
459 case -54:
return QStringLiteral(
"CL_INVALID_WORK_GROUP_SIZE" );
460 case -55:
return QStringLiteral(
"CL_INVALID_WORK_ITEM_SIZE" );
461 case -56:
return QStringLiteral(
"CL_INVALID_GLOBAL_OFFSET" );
462 case -57:
return QStringLiteral(
"CL_INVALID_EVENT_WAIT_LIST" );
463 case -58:
return QStringLiteral(
"CL_INVALID_EVENT" );
464 case -59:
return QStringLiteral(
"CL_INVALID_OPERATION" );
465 case -60:
return QStringLiteral(
"CL_INVALID_GL_OBJECT" );
466 case -61:
return QStringLiteral(
"CL_INVALID_BUFFER_SIZE" );
467 case -62:
return QStringLiteral(
"CL_INVALID_MIP_LEVEL" );
468 case -63:
return QStringLiteral(
"CL_INVALID_GLOBAL_WORK_SIZE" );
469 case -64:
return QStringLiteral(
"CL_INVALID_PROPERTY" );
470 case -65:
return QStringLiteral(
"CL_INVALID_IMAGE_DESCRIPTOR" );
471 case -66:
return QStringLiteral(
"CL_INVALID_COMPILER_OPTIONS" );
472 case -67:
return QStringLiteral(
"CL_INVALID_LINKER_OPTIONS" );
473 case -68:
return QStringLiteral(
"CL_INVALID_DEVICE_PARTITION_COUNT" );
474 case -69:
return QStringLiteral(
"CL_INVALID_PIPE_SIZE" );
475 case -70:
return QStringLiteral(
"CL_INVALID_DEVICE_QUEUE" );
476 case -71:
return QStringLiteral(
"CL_INVALID_SPEC_ID" );
477 case -72:
return QStringLiteral(
"CL_MAX_SIZE_RESTRICTION_EXCEEDED" );
478 case -1002:
return QStringLiteral(
"CL_INVALID_D3D10_DEVICE_KHR" );
479 case -1003:
return QStringLiteral(
"CL_INVALID_D3D10_RESOURCE_KHR" );
480 case -1004:
return QStringLiteral(
"CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR" );
481 case -1005:
return QStringLiteral(
"CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR" );
482 case -1006:
return QStringLiteral(
"CL_INVALID_D3D11_DEVICE_KHR" );
483 case -1007:
return QStringLiteral(
"CL_INVALID_D3D11_RESOURCE_KHR" );
484 case -1008:
return QStringLiteral(
"CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR" );
485 case -1009:
return QStringLiteral(
"CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR" );
486 case -1010:
return QStringLiteral(
"CL_INVALID_DX9_MEDIA_ADAPTER_KHR" );
487 case -1011:
return QStringLiteral(
"CL_INVALID_DX9_MEDIA_SURFACE_KHR" );
488 case -1012:
return QStringLiteral(
"CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR" );
489 case -1013:
return QStringLiteral(
"CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR" );
490 case -1093:
return QStringLiteral(
"CL_INVALID_EGL_OBJECT_KHR" );
491 case -1092:
return QStringLiteral(
"CL_EGL_RESOURCE_NOT_ACQUIRED_KHR" );
492 case -1001:
return QStringLiteral(
"CL_PLATFORM_NOT_FOUND_KHR" );
493 case -1057:
return QStringLiteral(
"CL_DEVICE_PARTITION_FAILED_EXT" );
494 case -1058:
return QStringLiteral(
"CL_INVALID_PARTITION_COUNT_EXT" );
495 case -1059:
return QStringLiteral(
"CL_INVALID_PARTITION_NAME_EXT" );
496 case -1094:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_INTEL" );
497 case -1095:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_TYPE_INTEL" );
498 case -1096:
return QStringLiteral(
"CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL" );
499 case -1097:
return QStringLiteral(
"CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL" );
500 case -1000:
return QStringLiteral(
"CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR" );
501 case -1098:
return QStringLiteral(
"CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL" );
502 case -1099:
return QStringLiteral(
"CL_INVALID_VA_API_MEDIA_SURFACE_INTEL" );
503 case -1100:
return QStringLiteral(
"CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL" );
504 case -1101:
return QStringLiteral(
"CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL" );
505 default:
return QStringLiteral(
"CL_UNKNOWN_ERROR" );
517 return cl::CommandQueue( context );
522 cl_command_queue_properties properties = 0;
524 cl_command_queue queue = clCreateCommandQueue(
context(), device(), properties,
nullptr );
526 return cl::CommandQueue( queue,
true );
533 static std::once_flag contextCreated;
534 std::call_once( contextCreated, [ = ]()
536 if (
available() && cl::Platform::getDefault()() && cl::Device::getDefault()() )
538 context = cl::Context( cl::Device::getDefault() );
560 if ( ok && version < 2.0f )
562 program.build( QStringLiteral(
"-cl-std=CL%1 -I%2" )
568 program.build( QStringLiteral(
"-I%1" )
572 catch ( cl::BuildError &e )
575 if ( build_log.isEmpty() )
576 build_log = QObject::tr(
"Build logs not available!" );
577 QString err = QObject::tr(
"Error building OpenCL program: %1" )
580 if ( exceptionBehavior ==
Throw )
583 catch ( cl::Error &e )
585 QString err = QObject::tr(
"Error %1 building OpenCL program in %2" )
586 .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.