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