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