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