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