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