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