QGIS API Documentation  3.12.1-București (121cc00ff0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 = QLatin1Literal( "OpenClEnabled" );
33 QLatin1String QgsOpenClUtils::SETTINGS_DEFAULT_DEVICE_KEY = QLatin1Literal( "OpenClDefaultDevice" );
34 QLatin1String QgsOpenClUtils::LOGMESSAGE_TAG = QLatin1Literal( "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 
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 
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 
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 }
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 (&#39;.cl&#39; extension is automatically ...
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:731
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...
The QgsOpenClUtils class is responsible for common OpenCL operations such as.
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.
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
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
Definition: qgis.h:732
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.