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