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