QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsopenclutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsopenclutils.cpp - QgsOpenClUtils
3 
4  ---------------------
5  begin : 11.4.2018
6  copyright : (C) 2018 by elpaso
7  email : elpaso at itopen dot it
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 #include "qgsopenclutils.h"
17 #include "qgssettings.h"
18 #include "qgsmessagelog.h"
19 #include "qgslogger.h"
20 
21 #include <QLibrary>
22 
23 #include <QTextStream>
24 #include <QFile>
25 #include <QDebug>
26 
27 #ifdef Q_OS_WIN
28 #include <windows.h>
29 #include <tchar.h>
30 #endif
31 
32 QLatin1String QgsOpenClUtils::SETTINGS_GLOBAL_ENABLED_KEY = QLatin1String( "OpenClEnabled" );
33 QLatin1String QgsOpenClUtils::SETTINGS_DEFAULT_DEVICE_KEY = QLatin1String( "OpenClDefaultDevice" );
34 QLatin1String QgsOpenClUtils::LOGMESSAGE_TAG = QLatin1String( "OpenCL" );
35 bool QgsOpenClUtils::sAvailable = false;
36 
37 Q_GLOBAL_STATIC( QString, sSourcePath )
38 
39 
40 const std::vector<cl::Device> QgsOpenClUtils::devices()
41 {
42  std::vector<cl::Platform> platforms;
43  cl::Platform::get( &platforms );
44  std::vector<cl::Device> existingDevices;
45  for ( const auto &p : platforms )
46  {
47  const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
48  QgsMessageLog::logMessage( QObject::tr( "Found OpenCL platform %1: %2" )
49  .arg( QString::fromStdString( platver ),
50  QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
51  LOGMESSAGE_TAG, Qgis::MessageLevel::Info );
52  if ( platver.find( "OpenCL " ) != std::string::npos )
53  {
54  std::vector<cl::Device> _devices;
55  // Check for a device
56  try
57  {
58  p.getDevices( CL_DEVICE_TYPE_ALL, &_devices );
59  }
60  catch ( cl::Error &e )
61  {
62  QgsMessageLog::logMessage( QObject::tr( "Error %1 on platform %3 searching for OpenCL device: %2" )
63  .arg( errorText( e.err() ),
64  QString::fromStdString( e.what() ),
65  QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ),
66  LOGMESSAGE_TAG, Qgis::MessageLevel::Warning );
67  }
68  if ( _devices.size() > 0 )
69  {
70  for ( unsigned long i = 0; i < _devices.size(); i++ )
71  {
72  QgsMessageLog::logMessage( QObject::tr( "Found OpenCL device: %1" )
73  .arg( deviceId( _devices[i] ) ),
74  LOGMESSAGE_TAG, Qgis::MessageLevel::Info );
75  existingDevices.push_back( _devices[i] );
76  }
77  }
78  }
79  }
80  return existingDevices;
81 }
82 
83 void QgsOpenClUtils::init()
84 {
85  static std::once_flag initialized;
86  std::call_once( initialized, [ = ]( )
87  {
88 #ifdef Q_OS_MAC
89  QLibrary openCLLib { QStringLiteral( "/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL" ) };
90 #else
91  QLibrary openCLLib { QStringLiteral( "OpenCL" ) };
92 #endif
93  openCLLib.setLoadHints( QLibrary::LoadHint::ResolveAllSymbolsHint );
94  if ( ! openCLLib.load() )
95  {
96  QgsMessageLog::logMessage( QObject::tr( "Error loading OpenCL library: %1" )
97  .arg( openCLLib.errorString() ),
98  LOGMESSAGE_TAG, Qgis::MessageLevel::Critical );
99  return;
100  }
101 
102 #ifdef Q_OS_WIN
103  HMODULE hModule = GetModuleHandle( "OpenCL.dll" );
104  if ( hModule )
105  {
106  TCHAR pszFileName[1024];
107  if ( GetModuleFileName( hModule, pszFileName, 1024 ) < 1024 )
108  {
109  QgsMessageLog::logMessage( QObject::tr( "Found OpenCL library filename %1" )
110  .arg( pszFileName ),
111  LOGMESSAGE_TAG, Qgis::MessageLevel::Info );
112 
113  DWORD dwUseless;
114  DWORD dwLen = GetFileVersionInfoSize( pszFileName, &dwUseless );
115  if ( dwLen )
116  {
117  LPTSTR lpVI = ( LPSTR ) malloc( dwLen );
118  if ( lpVI )
119  {
120  if ( GetFileVersionInfo( pszFileName, NULL, dwLen, lpVI ) )
121  {
122  VS_FIXEDFILEINFO *lpFFI;
123  if ( VerQueryValue( lpVI, "\\", ( LPVOID * ) &lpFFI, ( UINT * ) &dwUseless ) )
124  {
125  QgsMessageLog::logMessage( QObject::tr( "OpenCL Product version: %1.%2.%3.%4" )
126  .arg( lpFFI->dwProductVersionMS >> 16 )
127  .arg( lpFFI->dwProductVersionMS & 0xffff )
128  .arg( lpFFI->dwProductVersionLS >> 16 )
129  .arg( lpFFI->dwProductVersionLS & 0xffff ),
130  LOGMESSAGE_TAG, Qgis::MessageLevel::Info );
131  }
132 
133  struct LANGANDCODEPAGE
134  {
135  WORD wLanguage;
136  WORD wCodePage;
137  } *lpTranslate;
138 
139  DWORD cbTranslate;
140 
141  if ( VerQueryValue( lpVI, _T( "\\VarFileInfo\\Translation" ), ( LPVOID * ) &lpTranslate, ( UINT * ) &cbTranslate ) && cbTranslate >= sizeof( struct LANGANDCODEPAGE ) )
142  {
143  QStringList items = QStringList()
144  << QStringLiteral( "Comments" )
145  << QStringLiteral( "InternalName" )
146  << QStringLiteral( "ProductName" )
147  << QStringLiteral( "CompanyName" )
148  << QStringLiteral( "LegalCopyright" )
149  << QStringLiteral( "ProductVersion" )
150  << QStringLiteral( "FileDescription" )
151  << QStringLiteral( "LegalTrademarks" )
152  << QStringLiteral( "PrivateBuild" )
153  << QStringLiteral( "FileVersion" )
154  << QStringLiteral( "OriginalFilename" )
155  << QStringLiteral( "SpecialBuild" );
156  for ( auto d : items )
157  {
158  LPTSTR lpBuffer;
159  QString subBlock = QString( QStringLiteral( "\\StringFileInfo\\%1%2\\%3" ) )
160  .arg( lpTranslate[0].wLanguage, 4, 16, QLatin1Char( '0' ) )
161  .arg( lpTranslate[0].wCodePage, 4, 16, QLatin1Char( '0' ) )
162  .arg( d );
163 
164  QgsDebugMsg( QString( "d:%1 subBlock:%2" ).arg( d ).arg( subBlock ) );
165 
166  BOOL r = VerQueryValue( lpVI, subBlock.toUtf8(), ( LPVOID * )&lpBuffer, ( UINT * )&dwUseless );
167 
168  if ( r && lpBuffer && lpBuffer != INVALID_HANDLE_VALUE && dwUseless < 1023 )
169  {
170  QgsMessageLog::logMessage( QObject::tr( "Found OpenCL version info %1: %2" )
171  .arg( d )
172  .arg( QString::fromLocal8Bit( lpBuffer ) ),
173  LOGMESSAGE_TAG, Qgis::MessageLevel::Info );
174  }
175  }
176  }
177  }
178 
179  free( lpVI );
180  }
181  }
182  }
183  else
184  {
185  QgsMessageLog::logMessage( QObject::tr( "No module handle to OpenCL library" ), LOGMESSAGE_TAG, Qgis::MessageLevel::Warning );
186  }
187  }
188  else
189  {
190  QgsMessageLog::logMessage( QObject::tr( "No module handle to OpenCL library" ), LOGMESSAGE_TAG, Qgis::MessageLevel::Warning );
191  }
192 #endif
193 
194  try
195  {
196  activate( preferredDevice() );
197  }
198  catch ( cl::Error &e )
199  {
200  QgsMessageLog::logMessage( QObject::tr( "Error %1 initializing OpenCL device: %2" )
201  .arg( errorText( e.err() ), QString::fromStdString( e.what() ) ),
202  LOGMESSAGE_TAG, Qgis::MessageLevel::Critical );
203  }
204 
205  } );
206 }
207 
209 {
210  return *sSourcePath();
211 }
212 
213 void QgsOpenClUtils::setSourcePath( const QString &value )
214 {
215  *sSourcePath() = value;
216 }
217 
219 {
220  return deviceInfo( infoType, activeDevice( ) );
221 }
222 
223 QString QgsOpenClUtils::deviceInfo( const Info infoType, cl::Device device )
224 {
225  try
226  {
227  switch ( infoType )
228  {
229  case Info::Vendor:
230  return QString::fromStdString( device.getInfo<CL_DEVICE_VENDOR>() );
231  case Info::Profile:
232  return QString::fromStdString( device.getInfo<CL_DEVICE_PROFILE>() );
233  case Info::Version:
234  return QString::fromStdString( device.getInfo<CL_DEVICE_VERSION>() );
235  case Info::ImageSupport:
236  return device.getInfo<CL_DEVICE_IMAGE_SUPPORT>() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
237  case Info::Image2dMaxHeight:
238  return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>() );
239  case Info::MaxMemAllocSize:
240  return QString::number( device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>() );
241  case Info::Image2dMaxWidth:
242  return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() );
243  case Info::Type:
244  {
245  const unsigned long type( device.getInfo<CL_DEVICE_TYPE>() );
246  int mappedType;
247  switch ( type )
248  {
249  case CL_DEVICE_TYPE_CPU:
250  mappedType = QgsOpenClUtils::HardwareType::CPU;
251  break;
252  case CL_DEVICE_TYPE_GPU:
253  mappedType = QgsOpenClUtils::HardwareType::GPU;
254  break;
255  default:
256  mappedType = QgsOpenClUtils::HardwareType::Other;
257  }
258  const QMetaEnum metaEnum = QMetaEnum::fromType<QgsOpenClUtils::HardwareType>();
259  return metaEnum.valueToKey( mappedType );
260  }
261  case Info::Name:
262  return QString::fromStdString( device.getInfo<CL_DEVICE_NAME>() );
263  }
264  }
265  catch ( cl::Error &e )
266  {
267  // This can be a legitimate error when initializing, let's log it quietly
268  QgsDebugMsgLevel( QStringLiteral( "Error %1 getting info for OpenCL device: %2" )
269  .arg( errorText( e.err() ), QString::fromStdString( e.what() ) ),
270  4 );
271  return QString();
272  }
273  return QString();
274 }
275 
276 
278 {
279  return QgsSettings().value( SETTINGS_GLOBAL_ENABLED_KEY, false, QgsSettings::Section::Core ).toBool();
280 }
281 
283 {
284  return cl::Device::getDefault();
285 }
286 
288 {
289  QString version;
290  if ( cl::Platform::getDefault()() )
291  {
292  const std::string platver = cl::Platform::getDefault().getInfo<CL_PLATFORM_VERSION>();
293  if ( platver.find( "OpenCL " ) != std::string::npos )
294  {
295  version = QString::fromStdString( platver.substr( 7 ) ).split( ' ' ).first();
296  }
297  }
298  return version;
299 }
300 
301 void QgsOpenClUtils::storePreferredDevice( const QString deviceId )
302 {
303  QgsSettings().setValue( SETTINGS_DEFAULT_DEVICE_KEY, deviceId, QgsSettings::Section::Core );
304 }
305 
307 {
308  return QgsSettings().value( SETTINGS_DEFAULT_DEVICE_KEY, QString( ), QgsSettings::Section::Core ).toString();
309 }
310 
311 QString QgsOpenClUtils::deviceId( const cl::Device device )
312 {
313  return QStringLiteral( "%1|%2|%3|%4" )
314  .arg( deviceInfo( QgsOpenClUtils::Info::Name, device ) )
315  .arg( deviceInfo( QgsOpenClUtils::Info::Vendor, device ) )
316  .arg( deviceInfo( QgsOpenClUtils::Info::Version, device ) )
317  .arg( deviceInfo( QgsOpenClUtils::Info::Type, device ) );
318 }
319 
320 bool QgsOpenClUtils::activate( const QString &preferredDeviceId )
321 {
322  if ( deviceId( activeDevice() ) == preferredDeviceId )
323  {
324  sAvailable = true;
325  return false;
326  }
327  try
328  {
329  std::vector<cl::Platform> platforms;
330  cl::Platform::get( &platforms );
331  cl::Platform plat;
332  cl::Device dev;
333  bool deviceFound = false;
334  for ( const auto &p : platforms )
335  {
336  if ( deviceFound )
337  break;
338  const std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
339  QgsDebugMsg( QStringLiteral( "Found OpenCL platform %1: %2" ).arg( QString::fromStdString( platver ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
340  if ( platver.find( "OpenCL " ) != std::string::npos )
341  {
342  std::vector<cl::Device> devices;
343  // Search for a device
344  try
345  {
346  p.getDevices( CL_DEVICE_TYPE_ALL, &devices );
347  // First search for the preferred device
348  if ( ! preferredDeviceId.isEmpty() )
349  {
350  for ( const auto &_dev : devices )
351  {
352  if ( preferredDeviceId == deviceId( _dev ) )
353  {
354  // Got one!
355  plat = p;
356  dev = _dev;
357  deviceFound = true;
358  break;
359  }
360  }
361  }
362  // Not found or preferred device id not set: get the first GPU
363  if ( ! deviceFound )
364  {
365  for ( const auto &_dev : devices )
366  {
367  if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
368  {
369  // Got one!
370  plat = p;
371  dev = _dev;
372  deviceFound = true;
373  break;
374  }
375  }
376  }
377  // Still nothing? Get the first device
378  if ( ! deviceFound )
379  {
380  for ( const auto &_dev : devices )
381  {
382  if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU )
383  {
384  // Got one!
385  plat = p;
386  dev = _dev;
387  deviceFound = true;
388  break;
389  }
390  }
391  }
392  if ( ! deviceFound )
393  {
394  QgsMessageLog::logMessage( QObject::tr( "No OpenCL device could be found." ), LOGMESSAGE_TAG, Qgis::MessageLevel::Warning );
395  }
396  }
397  catch ( cl::Error &e )
398  {
399  QgsDebugMsg( QStringLiteral( "Error %1 on platform %3 searching for OpenCL device: %2" )
400  .arg( errorText( e.err() ),
401  QString::fromStdString( e.what() ),
402  QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
403  }
404 
405  }
406  }
407  if ( ! plat() )
408  {
409  QgsMessageLog::logMessage( QObject::tr( "No OpenCL platform found." ), LOGMESSAGE_TAG, Qgis::MessageLevel::Warning );
410  sAvailable = false;
411  }
412  else
413  {
414  const cl::Platform newP = cl::Platform::setDefault( plat );
415  if ( newP != plat )
416  {
417  QgsMessageLog::logMessage( QObject::tr( "Error setting default platform." ),
418  LOGMESSAGE_TAG, Qgis::MessageLevel::Warning );
419  sAvailable = false;
420  }
421  else
422  {
423  cl::Device::setDefault( dev );
424  QgsMessageLog::logMessage( QObject::tr( "Active OpenCL device: %1" )
425  .arg( QString::fromStdString( dev.getInfo<CL_DEVICE_NAME>() ) ),
426  LOGMESSAGE_TAG, Qgis::MessageLevel::Success );
427  sAvailable = true;
428  }
429  }
430  }
431 
432  catch ( cl::Error &e )
433  {
434  QgsMessageLog::logMessage( QObject::tr( "Error %1 searching for OpenCL device: %2" )
435  .arg( errorText( e.err() ), QString::fromStdString( e.what() ) ),
436  LOGMESSAGE_TAG, Qgis::MessageLevel::Warning );
437  sAvailable = false;
438  }
439  return sAvailable;
440 }
441 
442 QString QgsOpenClUtils::deviceDescription( const cl::Device device )
443 {
444  return QStringLiteral(
445  "Type: <b>%9</b><br>"
446  "Name: <b>%1</b><br>"
447  "Vendor: <b>%2</b><br>"
448  "Profile: <b>%3</b><br>"
449  "Version: <b>%4</b><br>"
450  "Image support: <b>%5</b><br>"
451  "Max image2d width: <b>%6</b><br>"
452  "Max image2d height: <b>%7</b><br>"
453  "Max mem alloc size: <b>%8</b><br>"
454  ).arg( QgsOpenClUtils::deviceInfo( QgsOpenClUtils::Info::Name, device ),
455  QgsOpenClUtils::deviceInfo( QgsOpenClUtils::Info::Vendor, device ),
456  QgsOpenClUtils::deviceInfo( QgsOpenClUtils::Info::Profile, device ),
457  QgsOpenClUtils::deviceInfo( QgsOpenClUtils::Info::Version, device ),
458  QgsOpenClUtils::deviceInfo( QgsOpenClUtils::Info::ImageSupport, device ),
459  QgsOpenClUtils::deviceInfo( QgsOpenClUtils::Info::Image2dMaxWidth, device ),
460  QgsOpenClUtils::deviceInfo( QgsOpenClUtils::Info::Image2dMaxHeight, device ),
461  QgsOpenClUtils::deviceInfo( QgsOpenClUtils::Info::MaxMemAllocSize, device ),
462  QgsOpenClUtils::deviceInfo( QgsOpenClUtils::Info::Type, device ) );
463 }
464 
465 QString QgsOpenClUtils::deviceDescription( const QString deviceId )
466 {
467  for ( const auto &dev : devices( ) )
468  {
469  if ( QgsOpenClUtils::deviceId( dev ) == deviceId )
470  return deviceDescription( dev );
471  }
472  return QString();
473 }
474 
476 {
477  init();
478  return sAvailable;
479 }
480 
481 void QgsOpenClUtils::setEnabled( bool enabled )
482 {
483  QgsSettings().setValue( SETTINGS_GLOBAL_ENABLED_KEY, enabled, QgsSettings::Section::Core );
484 }
485 
486 
487 
488 QString QgsOpenClUtils::sourceFromPath( const QString &path )
489 {
490  // TODO: check for compatibility with current platform ( cl_khr_fp64 )
491  // Try to load the program sources
492  QString source_str;
493  QFile file( path );
494  if ( file.open( QFile::ReadOnly | QFile::Text ) )
495  {
496  QTextStream in( &file );
497  source_str = in.readAll();
498  file.close();
499  }
500  else
501  {
502  QgsMessageLog::logMessage( QObject::tr( "Could not load OpenCL program from path %1." ).arg( path ), LOGMESSAGE_TAG, Qgis::MessageLevel::Warning );
503  }
504  return source_str;
505 }
506 
507 QString QgsOpenClUtils::sourceFromBaseName( const QString &baseName )
508 {
509  const QString path = QStringLiteral( "%1/%2.cl" ).arg( sourcePath(), baseName );
510  return sourceFromPath( path );
511 }
512 
513 QString QgsOpenClUtils::buildLog( cl::BuildError &error )
514 {
515  cl::BuildLogType build_logs = error.getBuildLog();
516  QString build_log;
517  if ( build_logs.size() > 0 )
518  build_log = QString::fromStdString( build_logs[0].second );
519  return build_log;
520 }
521 
522 QString QgsOpenClUtils::errorText( const int errorCode )
523 {
524  switch ( errorCode )
525  {
526  case 0: return QStringLiteral( "CL_SUCCESS" );
527  case -1: return QStringLiteral( "CL_DEVICE_NOT_FOUND" );
528  case -2: return QStringLiteral( "CL_DEVICE_NOT_AVAILABLE" );
529  case -3: return QStringLiteral( "CL_COMPILER_NOT_AVAILABLE" );
530  case -4: return QStringLiteral( "CL_MEM_OBJECT_ALLOCATION_FAILURE" );
531  case -5: return QStringLiteral( "CL_OUT_OF_RESOURCES" );
532  case -6: return QStringLiteral( "CL_OUT_OF_HOST_MEMORY" );
533  case -7: return QStringLiteral( "CL_PROFILING_INFO_NOT_AVAILABLE" );
534  case -8: return QStringLiteral( "CL_MEM_COPY_OVERLAP" );
535  case -9: return QStringLiteral( "CL_IMAGE_FORMAT_MISMATCH" );
536  case -10: return QStringLiteral( "CL_IMAGE_FORMAT_NOT_SUPPORTED" );
537  case -12: return QStringLiteral( "CL_MAP_FAILURE" );
538  case -13: return QStringLiteral( "CL_MISALIGNED_SUB_BUFFER_OFFSET" );
539  case -14: return QStringLiteral( "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST" );
540  case -15: return QStringLiteral( "CL_COMPILE_PROGRAM_FAILURE" );
541  case -16: return QStringLiteral( "CL_LINKER_NOT_AVAILABLE" );
542  case -17: return QStringLiteral( "CL_LINK_PROGRAM_FAILURE" );
543  case -18: return QStringLiteral( "CL_DEVICE_PARTITION_FAILED" );
544  case -19: return QStringLiteral( "CL_KERNEL_ARG_INFO_NOT_AVAILABLE" );
545  case -30: return QStringLiteral( "CL_INVALID_VALUE" );
546  case -31: return QStringLiteral( "CL_INVALID_DEVICE_TYPE" );
547  case -32: return QStringLiteral( "CL_INVALID_PLATFORM" );
548  case -33: return QStringLiteral( "CL_INVALID_DEVICE" );
549  case -34: return QStringLiteral( "CL_INVALID_CONTEXT" );
550  case -35: return QStringLiteral( "CL_INVALID_QUEUE_PROPERTIES" );
551  case -36: return QStringLiteral( "CL_INVALID_COMMAND_QUEUE" );
552  case -37: return QStringLiteral( "CL_INVALID_HOST_PTR" );
553  case -38: return QStringLiteral( "CL_INVALID_MEM_OBJECT" );
554  case -39: return QStringLiteral( "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR" );
555  case -40: return QStringLiteral( "CL_INVALID_IMAGE_SIZE" );
556  case -41: return QStringLiteral( "CL_INVALID_SAMPLER" );
557  case -42: return QStringLiteral( "CL_INVALID_BINARY" );
558  case -43: return QStringLiteral( "CL_INVALID_BUILD_OPTIONS" );
559  case -44: return QStringLiteral( "CL_INVALID_PROGRAM" );
560  case -45: return QStringLiteral( "CL_INVALID_PROGRAM_EXECUTABLE" );
561  case -46: return QStringLiteral( "CL_INVALID_KERNEL_NAME" );
562  case -47: return QStringLiteral( "CL_INVALID_KERNEL_DEFINITION" );
563  case -48: return QStringLiteral( "CL_INVALID_KERNEL" );
564  case -49: return QStringLiteral( "CL_INVALID_ARG_INDEX" );
565  case -50: return QStringLiteral( "CL_INVALID_ARG_VALUE" );
566  case -51: return QStringLiteral( "CL_INVALID_ARG_SIZE" );
567  case -52: return QStringLiteral( "CL_INVALID_KERNEL_ARGS" );
568  case -53: return QStringLiteral( "CL_INVALID_WORK_DIMENSION" );
569  case -54: return QStringLiteral( "CL_INVALID_WORK_GROUP_SIZE" );
570  case -55: return QStringLiteral( "CL_INVALID_WORK_ITEM_SIZE" );
571  case -56: return QStringLiteral( "CL_INVALID_GLOBAL_OFFSET" );
572  case -57: return QStringLiteral( "CL_INVALID_EVENT_WAIT_LIST" );
573  case -58: return QStringLiteral( "CL_INVALID_EVENT" );
574  case -59: return QStringLiteral( "CL_INVALID_OPERATION" );
575  case -60: return QStringLiteral( "CL_INVALID_GL_OBJECT" );
576  case -61: return QStringLiteral( "CL_INVALID_BUFFER_SIZE" );
577  case -62: return QStringLiteral( "CL_INVALID_MIP_LEVEL" );
578  case -63: return QStringLiteral( "CL_INVALID_GLOBAL_WORK_SIZE" );
579  case -64: return QStringLiteral( "CL_INVALID_PROPERTY" );
580  case -65: return QStringLiteral( "CL_INVALID_IMAGE_DESCRIPTOR" );
581  case -66: return QStringLiteral( "CL_INVALID_COMPILER_OPTIONS" );
582  case -67: return QStringLiteral( "CL_INVALID_LINKER_OPTIONS" );
583  case -68: return QStringLiteral( "CL_INVALID_DEVICE_PARTITION_COUNT" );
584  case -69: return QStringLiteral( "CL_INVALID_PIPE_SIZE" );
585  case -70: return QStringLiteral( "CL_INVALID_DEVICE_QUEUE" );
586  case -71: return QStringLiteral( "CL_INVALID_SPEC_ID" );
587  case -72: return QStringLiteral( "CL_MAX_SIZE_RESTRICTION_EXCEEDED" );
588  case -1002: return QStringLiteral( "CL_INVALID_D3D10_DEVICE_KHR" );
589  case -1003: return QStringLiteral( "CL_INVALID_D3D10_RESOURCE_KHR" );
590  case -1004: return QStringLiteral( "CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR" );
591  case -1005: return QStringLiteral( "CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR" );
592  case -1006: return QStringLiteral( "CL_INVALID_D3D11_DEVICE_KHR" );
593  case -1007: return QStringLiteral( "CL_INVALID_D3D11_RESOURCE_KHR" );
594  case -1008: return QStringLiteral( "CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR" );
595  case -1009: return QStringLiteral( "CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR" );
596  case -1010: return QStringLiteral( "CL_INVALID_DX9_MEDIA_ADAPTER_KHR" );
597  case -1011: return QStringLiteral( "CL_INVALID_DX9_MEDIA_SURFACE_KHR" );
598  case -1012: return QStringLiteral( "CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR" );
599  case -1013: return QStringLiteral( "CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR" );
600  case -1093: return QStringLiteral( "CL_INVALID_EGL_OBJECT_KHR" );
601  case -1092: return QStringLiteral( "CL_EGL_RESOURCE_NOT_ACQUIRED_KHR" );
602  case -1001: return QStringLiteral( "CL_PLATFORM_NOT_FOUND_KHR" );
603  case -1057: return QStringLiteral( "CL_DEVICE_PARTITION_FAILED_EXT" );
604  case -1058: return QStringLiteral( "CL_INVALID_PARTITION_COUNT_EXT" );
605  case -1059: return QStringLiteral( "CL_INVALID_PARTITION_NAME_EXT" );
606  case -1094: return QStringLiteral( "CL_INVALID_ACCELERATOR_INTEL" );
607  case -1095: return QStringLiteral( "CL_INVALID_ACCELERATOR_TYPE_INTEL" );
608  case -1096: return QStringLiteral( "CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL" );
609  case -1097: return QStringLiteral( "CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL" );
610  case -1000: return QStringLiteral( "CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR" );
611  case -1098: return QStringLiteral( "CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL" );
612  case -1099: return QStringLiteral( "CL_INVALID_VA_API_MEDIA_SURFACE_INTEL" );
613  case -1100: return QStringLiteral( "CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL" );
614  case -1101: return QStringLiteral( "CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL" );
615  default: return QStringLiteral( "CL_UNKNOWN_ERROR" );
616  }
617 }
618 
620 {
621  // Depending on the platform version, to avoid a crash
622  // we need to use the legacy calls to C API instead of the 2.0
623  // compatible C++ API.
624  cl::Context context( QgsOpenClUtils::context() );
625  if ( QgsOpenClUtils::activePlatformVersion().toFloat() >= 200 )
626  {
627  return cl::CommandQueue( context );
628  }
629  else // legacy
630  {
631  cl::Device device( QgsOpenClUtils::activeDevice() );
632  const cl_command_queue_properties properties = 0;
634  cl_command_queue queue = clCreateCommandQueue( context(), device(), properties, nullptr );
636  return cl::CommandQueue( queue, true );
637  }
638 }
639 
641 {
642  static cl::Context context;
643  static std::once_flag contextCreated;
644  std::call_once( contextCreated, [ = ]()
645  {
646  if ( available() && cl::Platform::getDefault()() && cl::Device::getDefault()() )
647  {
648  context = cl::Context( cl::Device::getDefault() );
649  }
650  } );
651  return context;
652 }
653 
654 cl::Program QgsOpenClUtils::buildProgram( const cl::Context &, const QString &source, ExceptionBehavior exceptionBehavior )
655 {
656  // Deprecated: ignore context and use default
657  return buildProgram( source, exceptionBehavior );
658 }
659 
660 cl::Program QgsOpenClUtils::buildProgram( const QString &source, QgsOpenClUtils::ExceptionBehavior exceptionBehavior )
661 {
662  cl::Program program;
663  try
664  {
665  program = cl::Program( QgsOpenClUtils::context(), source.toStdString( ) );
666  // OpenCL version for compatibility with older hardware, but it's up to
667  // llvm to support latest CL versions
668  bool ok;
669  const float version( QgsOpenClUtils::activePlatformVersion().toFloat( &ok ) );
670  if ( ok && version < 2.0f )
671  {
672  program.build( QStringLiteral( "-cl-std=CL%1 -I\"%2\"" )
674  .arg( sourcePath() ).toStdString().c_str() );
675  }
676  else
677  {
678  program.build( QStringLiteral( "-I\"%1\"" )
679  .arg( sourcePath() ).toStdString().c_str() );
680  }
681  }
682  catch ( cl::BuildError &e )
683  {
684  QString build_log( buildLog( e ) );
685  if ( build_log.isEmpty() )
686  build_log = QObject::tr( "Build logs not available!" );
687  const QString err = QObject::tr( "Error building OpenCL program: %1" )
688  .arg( build_log );
689  QgsMessageLog::logMessage( err, LOGMESSAGE_TAG, Qgis::MessageLevel::Critical );
690  if ( exceptionBehavior == Throw )
691  throw e;
692  }
693  catch ( cl::Error &e )
694  {
695  const QString err = QObject::tr( "Error %1 building OpenCL program in %2" )
696  .arg( errorText( e.err() ), QString::fromStdString( e.what() ) );
697  QgsMessageLog::logMessage( err, LOGMESSAGE_TAG, Qgis::MessageLevel::Critical );
698  throw e;
699  }
700  return program;
701 }
QgsOpenClUtils::activeDeviceInfo
static QString activeDeviceInfo(const Info infoType=Info::Name)
Returns infoType information about the active (default) device.
Definition: qgsopenclutils.cpp:218
QgsOpenClUtils::errorText
static QString errorText(const int errorCode)
Returns a string representation from an OpenCL errorCode.
Definition: qgsopenclutils.cpp:522
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:161
QgsOpenClUtils::Info
Info
The Info enum maps to OpenCL info constants.
Definition: qgsopenclutils.h:111
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsOpenClUtils::deviceInfo
static QString deviceInfo(const Info infoType, cl::Device device)
Returns infoType information about the device.
Definition: qgsopenclutils.cpp:223
QgsOpenClUtils::Throw
@ Throw
Write errors in the message log and re-throw exceptions.
Definition: qgsopenclutils.h:91
QgsOpenClUtils::buildLog
static QString buildLog(cl::BuildError &error)
Extract and return the build log error from error.
Definition: qgsopenclutils.cpp:513
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsOpenClUtils::deviceDescription
static QString deviceDescription(const cl::Device device)
Returns a formatted description for the device.
Definition: qgsopenclutils.cpp:442
Q_GLOBAL_STATIC
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
QgsOpenClUtils::available
static bool available()
Checks whether a suitable OpenCL platform and device is available on this system and initialize the Q...
Definition: qgsopenclutils.cpp:475
QgsOpenClUtils::sourceFromPath
static QString sourceFromPath(const QString &path)
Read an OpenCL source file from path.
Definition: qgsopenclutils.cpp:488
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2820
QgsOpenClUtils::activeDevice
static cl::Device activeDevice()
Returns the active device.
Definition: qgsopenclutils.cpp:282
QgsOpenClUtils::preferredDevice
static QString preferredDevice()
Read from the settings the preferred device identifier.
Definition: qgsopenclutils.cpp:306
QgsMessageLog::logMessage
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).
Definition: qgsmessagelog.cpp:27
QgsOpenClUtils::sourceFromBaseName
static QString sourceFromBaseName(const QString &baseName)
Returns the full path to a an OpenCL source file from the baseName ('.cl' extension is automatically ...
Definition: qgsopenclutils.cpp:507
QgsOpenClUtils::enabled
static bool enabled()
Returns true if OpenCL is enabled in the user settings.
Definition: qgsopenclutils.cpp:277
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:279
QgsOpenClUtils::ExceptionBehavior
ExceptionBehavior
The ExceptionBehavior enum define how exceptions generated by OpenCL should be treated.
Definition: qgsopenclutils.h:88
QgsOpenClUtils::deviceId
static QString deviceId(const cl::Device device)
Create a string identifier from a device.
Definition: qgsopenclutils.cpp:311
QgsOpenClUtils::activePlatformVersion
static QString activePlatformVersion()
Returns the active platform OpenCL version string (e.g.
Definition: qgsopenclutils.cpp:287
QgsOpenClUtils::setEnabled
static void setEnabled(bool enabled)
Set the OpenCL user setting to enabled.
Definition: qgsopenclutils.cpp:481
QgsOpenClUtils::storePreferredDevice
static void storePreferredDevice(const QString deviceId)
Store in the settings the preferred deviceId device identifier.
Definition: qgsopenclutils.cpp:301
qgssettings.h
QgsOpenClUtils::commandQueue
static cl::CommandQueue commandQueue()
Create an OpenCL command queue from the default context.
Definition: qgsopenclutils.cpp:619
QgsOpenClUtils
The QgsOpenClUtils class is responsible for common OpenCL operations such as.
Definition: qgsopenclutils.h:79
QgsOpenClUtils::context
static cl::Context context()
Context factory.
Definition: qgsopenclutils.cpp:640
qgsopenclutils.h
qgslogger.h
QgsOpenClUtils::setSourcePath
static void setSourcePath(const QString &value)
Set the base path to OpenCL program directory.
Definition: qgsopenclutils.cpp:213
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2819
QgsOpenClUtils::LOGMESSAGE_TAG
static QLatin1String LOGMESSAGE_TAG
OpenCL string for message logs.
Definition: qgsopenclutils.h:189
QgsOpenClUtils::buildProgram
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...
Definition: qgsopenclutils.cpp:654
QgsOpenClUtils::sourcePath
static QString sourcePath()
Returns the base path to OpenCL program directory.
Definition: qgsopenclutils.cpp:208
QgsOpenClUtils::devices
static const std::vector< cl::Device > devices()
Returns a list of OpenCL devices found on this sysytem.
Definition: qgsopenclutils.cpp:40
qgsmessagelog.h