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