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