mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-27 00:33:48 -05:00
[opencl] Class docs improvements
Also try hard to find a device before giving up
This commit is contained in:
parent
6956436804
commit
86b60c6c63
@ -32,12 +32,10 @@ cl::Device QgsOpenClUtils::sActiveDevice = cl::Device();
|
||||
QString QgsOpenClUtils::sSourcePath = QString();
|
||||
|
||||
|
||||
std::vector<cl::Device> QgsOpenClUtils::devices()
|
||||
const std::vector<cl::Device> QgsOpenClUtils::devices()
|
||||
{
|
||||
std::vector<cl::Platform> platforms;
|
||||
cl::Platform::get( &platforms );
|
||||
cl::Platform plat;
|
||||
cl::Device dev;
|
||||
std::vector<cl::Device> existingDevices;
|
||||
for ( auto &p : platforms )
|
||||
{
|
||||
@ -91,7 +89,7 @@ void QgsOpenClUtils::init()
|
||||
|
||||
QString QgsOpenClUtils::sourcePath()
|
||||
{
|
||||
return sSourcePath.isEmpty() ? QStringLiteral( "./" ) : sSourcePath;
|
||||
return sSourcePath;
|
||||
}
|
||||
|
||||
void QgsOpenClUtils::setSourcePath( const QString &value )
|
||||
@ -99,7 +97,7 @@ void QgsOpenClUtils::setSourcePath( const QString &value )
|
||||
sSourcePath = value;
|
||||
}
|
||||
|
||||
QString QgsOpenClUtils::defaultDeviceInfo( const QgsOpenClUtils::Info infoType )
|
||||
QString QgsOpenClUtils::activeDeviceInfo( const QgsOpenClUtils::Info infoType )
|
||||
{
|
||||
return deviceInfo( infoType, activeDevice( ) );
|
||||
}
|
||||
@ -126,7 +124,7 @@ QString QgsOpenClUtils::deviceInfo( const Info infoType, cl::Device device )
|
||||
return QString::number( device.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() );
|
||||
case Info::Type:
|
||||
{
|
||||
int type( device.getInfo<CL_DEVICE_TYPE>() );
|
||||
unsigned long type( device.getInfo<CL_DEVICE_TYPE>() );
|
||||
int mappedType;
|
||||
switch ( type )
|
||||
{
|
||||
@ -143,7 +141,6 @@ QString QgsOpenClUtils::deviceInfo( const Info infoType, cl::Device device )
|
||||
return metaEnum.valueToKey( mappedType );
|
||||
}
|
||||
case Info::Name:
|
||||
default:
|
||||
return QString::fromStdString( device.getInfo<CL_DEVICE_NAME>() );
|
||||
}
|
||||
}
|
||||
@ -168,11 +165,6 @@ cl::Device QgsOpenClUtils::activeDevice()
|
||||
return sActiveDevice;
|
||||
}
|
||||
|
||||
void QgsOpenClUtils::setActiveDevice( const cl::Device device )
|
||||
{
|
||||
sActiveDevice = device;
|
||||
}
|
||||
|
||||
void QgsOpenClUtils::storePreferredDevice( const QString deviceId )
|
||||
{
|
||||
QgsSettings().setValue( SETTINGS_DEFAULT_DEVICE_KEY, deviceId, QgsSettings::Section::Core );
|
||||
@ -192,7 +184,7 @@ QString QgsOpenClUtils::deviceId( const cl::Device device )
|
||||
.arg( deviceInfo( QgsOpenClUtils::Info::Type, device ) );
|
||||
}
|
||||
|
||||
bool QgsOpenClUtils::activate( const QString preferredDeviceId )
|
||||
bool QgsOpenClUtils::activate( const QString &preferredDeviceId )
|
||||
{
|
||||
if ( deviceId( activeDevice() ) == preferredDeviceId )
|
||||
{
|
||||
@ -204,8 +196,11 @@ bool QgsOpenClUtils::activate( const QString preferredDeviceId )
|
||||
cl::Platform::get( &platforms );
|
||||
cl::Platform plat;
|
||||
cl::Device dev;
|
||||
bool deviceFound = false;
|
||||
for ( auto &p : platforms )
|
||||
{
|
||||
if ( deviceFound )
|
||||
break;
|
||||
std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
|
||||
QgsDebugMsg( QStringLiteral( "Found OpenCL platform %1: %2" ).arg( QString::fromStdString( platver ), QString::fromStdString( p.getInfo<CL_PLATFORM_NAME>() ) ) );
|
||||
if ( platver.find( "OpenCL 1." ) != std::string::npos )
|
||||
@ -215,30 +210,69 @@ bool QgsOpenClUtils::activate( const QString preferredDeviceId )
|
||||
try
|
||||
{
|
||||
p.getDevices( CL_DEVICE_TYPE_ALL, &devices );
|
||||
// First search for the preferred device
|
||||
if ( ! preferredDeviceId.isEmpty() )
|
||||
{
|
||||
for ( const auto &_dev : devices )
|
||||
{
|
||||
if ( preferredDeviceId == deviceId( _dev ) )
|
||||
{
|
||||
// Got one!
|
||||
plat = p;
|
||||
dev = _dev;
|
||||
deviceFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Not found or preferred device id not set: get the first GPU
|
||||
if ( ! deviceFound )
|
||||
{
|
||||
for ( const auto &_dev : devices )
|
||||
{
|
||||
if ( preferredDeviceId.isEmpty() && _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
|
||||
{
|
||||
// Got one!
|
||||
plat = p;
|
||||
dev = _dev;
|
||||
deviceFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Still nothing? Get the first device
|
||||
if ( ! deviceFound )
|
||||
{
|
||||
for ( const auto &_dev : devices )
|
||||
{
|
||||
if ( preferredDeviceId.isEmpty() && _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
|
||||
{
|
||||
// Got one!
|
||||
plat = p;
|
||||
dev = _dev;
|
||||
deviceFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ! deviceFound )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "No OpenCL 1.x device could be found." ), LOGMESSAGE_TAG, Qgis::Warning );
|
||||
}
|
||||
}
|
||||
catch ( cl::Error &e )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "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>() ) ), 2 );
|
||||
}
|
||||
for ( const auto &_dev : devices )
|
||||
{
|
||||
if ( ( preferredDeviceId.isEmpty() && _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU ) ||
|
||||
( preferredDeviceId == deviceId( _dev ) ) )
|
||||
{
|
||||
// Got one!
|
||||
plat = p;
|
||||
dev = _dev;
|
||||
break;
|
||||
}
|
||||
QgsDebugMsg( QStringLiteral( "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>() ) ) );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ( plat() == 0 )
|
||||
if ( ! plat() )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "No OpenCL 1.x platform with GPU found." ), LOGMESSAGE_TAG, Qgis::Warning );
|
||||
QgsMessageLog::logMessage( QObject::tr( "No OpenCL 1.x platform found." ), LOGMESSAGE_TAG, Qgis::Warning );
|
||||
sAvailable = false;
|
||||
}
|
||||
else
|
||||
@ -253,7 +287,7 @@ bool QgsOpenClUtils::activate( const QString preferredDeviceId )
|
||||
else
|
||||
{
|
||||
cl::Device::setDefault( dev );
|
||||
QgsMessageLog::logMessage( QObject::tr( "Activated OpenCL device %1" )
|
||||
QgsMessageLog::logMessage( QObject::tr( "Active OpenCL device: %1" )
|
||||
.arg( QString::fromStdString( dev.getInfo<CL_DEVICE_NAME>() ) ),
|
||||
LOGMESSAGE_TAG, Qgis::Success );
|
||||
sAvailable = true;
|
||||
@ -487,7 +521,7 @@ cl::Program QgsOpenClUtils::buildProgram( const cl::Context &context, const QStr
|
||||
}
|
||||
catch ( cl::Error &e )
|
||||
{
|
||||
QString err = QObject::tr( "Error %1 running OpenCL program in %2" )
|
||||
QString err = QObject::tr( "Error %1 building OpenCL program in %2" )
|
||||
.arg( errorText( e.err() ), QString::fromStdString( e.what() ) );
|
||||
QgsMessageLog::logMessage( err, LOGMESSAGE_TAG, Qgis::Critical );
|
||||
throw e;
|
||||
|
@ -34,12 +34,30 @@
|
||||
* \brief The QgsOpenClUtils class is responsible for common OpenCL operations such as
|
||||
* - enable/disable opencl
|
||||
* - store and retrieve preferences for the default device
|
||||
* - check opencl device availability and automatically choose the first GPU (TODO: let the user choose & override!)
|
||||
* - creating contexts
|
||||
* - check opencl device availability and automatically choose the first GPU device
|
||||
* - creating the default context
|
||||
* - loading program sources from standard locations
|
||||
* - build programs and log errors
|
||||
* \since QGIS 3.4
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* \code{.cpp}
|
||||
// This will check if OpenCL is enabled in user options and if there is a suitable
|
||||
// device, if a device is found it is initialized.
|
||||
if ( QgsOpenClUtils::enabled() && QgsOpenClUtils::available() )
|
||||
{
|
||||
// Use the default context
|
||||
cl::Context ctx = QgsOpenClUtils::context();
|
||||
cl::CommandQueue queue( ctx );
|
||||
// Load the program from a standard location and build it
|
||||
cl::Program program = QgsOpenClUtils::buildProgram( ctx, QgsOpenClUtils::sourceFromBaseName( QStringLiteral ( "hillshade" ) ) );
|
||||
// Continue with the usual OpenCL buffer, kernel and execution
|
||||
...
|
||||
}
|
||||
* \endcode
|
||||
*
|
||||
* \note not available in Python bindings
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class CORE_EXPORT QgsOpenClUtils
|
||||
{
|
||||
@ -52,8 +70,8 @@ class CORE_EXPORT QgsOpenClUtils
|
||||
*/
|
||||
enum ExceptionBehavior
|
||||
{
|
||||
Catch, // Write errors in the message log and silently fail
|
||||
Throw // Write errors in the message log and re-throw exceptions
|
||||
Catch, //! Write errors in the message log and silently fail
|
||||
Throw //! Write errors in the message log and re-throw exceptions
|
||||
};
|
||||
|
||||
/**
|
||||
@ -86,18 +104,32 @@ class CORE_EXPORT QgsOpenClUtils
|
||||
Type = CL_DEVICE_TYPE // CPU/GPU etc.
|
||||
};
|
||||
|
||||
//! Return true if OpenCL is enabled in the user settings
|
||||
/**
|
||||
* Checks whether a suitable OpenCL platform and device is available on this system
|
||||
* and initialize the QGIS OpenCL system by activating the preferred device
|
||||
* if specified in the user the settings, if no preferred device was set or
|
||||
* the preferred device could not be found the first GPU device is activated,
|
||||
* the first CPU device acts as a fallback if none of the previous could be found.
|
||||
*
|
||||
* This function must always be called before using QGIS OpenCL utils
|
||||
*/
|
||||
static bool available();
|
||||
|
||||
//! Returns true if OpenCL is enabled in the user settings
|
||||
static bool enabled();
|
||||
|
||||
//! Return a list of OpenCL devices found on this sysytem
|
||||
static std::vector<cl::Device> devices();
|
||||
//! Returns a list of OpenCL devices found on this sysytem
|
||||
static const std::vector<cl::Device> devices();
|
||||
|
||||
//! Return the active device
|
||||
/**
|
||||
* Returns the active device.
|
||||
*
|
||||
* The active device is set as the default device for all OpenCL operations,
|
||||
* once it is set it cannot be changed until QGIS is restarted (this is
|
||||
* due to the way the underlying OpenCL library is built).
|
||||
*/
|
||||
static cl::Device activeDevice( );
|
||||
|
||||
//! Set the active \a device
|
||||
static void setActiveDevice( const cl::Device device );
|
||||
|
||||
//! Store in the settings the preferred \a deviceId device identifier
|
||||
static void storePreferredDevice( const QString deviceId );
|
||||
|
||||
@ -107,15 +139,6 @@ class CORE_EXPORT QgsOpenClUtils
|
||||
//! Create a string identifier from a \a device
|
||||
static QString deviceId( const cl::Device device );
|
||||
|
||||
/**
|
||||
* Activate a device identified by its \a preferredDeviceId by making it the default device
|
||||
* if the device does not exists or deviceId is empty, the first GPU device will be
|
||||
* activated
|
||||
* \return true if the device could be found and activated. Return false if the device was already
|
||||
* the active one or if it could not be found.
|
||||
*/
|
||||
static bool activate( const QString preferredDeviceId = QString() );
|
||||
|
||||
/**
|
||||
* Returns a formatted description for the \a device
|
||||
*/
|
||||
@ -126,12 +149,6 @@ class CORE_EXPORT QgsOpenClUtils
|
||||
*/
|
||||
static QString deviceDescription( const QString deviceId );
|
||||
|
||||
/**
|
||||
* Checks whether a suitable OpenCL platform and device is found on this system and initialize the QGIS OpenCL system
|
||||
* This function must be called before using QGIS OpenCL utils
|
||||
*/
|
||||
static bool available();
|
||||
|
||||
//! Set the OpenCL user setting to \a enabled
|
||||
static void setEnabled( bool enabled );
|
||||
|
||||
@ -141,17 +158,17 @@ class CORE_EXPORT QgsOpenClUtils
|
||||
//! Read an OpenCL source file from \a path
|
||||
static QString sourceFromPath( const QString &path );
|
||||
|
||||
//! Return the full path to a an OpenCL source file from the \a baseName ('.cl' extension is automatically appended)
|
||||
//! Returns the full path to a an OpenCL source file from the \a baseName ('.cl' extension is automatically appended)
|
||||
static QString sourceFromBaseName( const QString &baseName );
|
||||
|
||||
//! OpenCL string for message logs
|
||||
static QLatin1String LOGMESSAGE_TAG;
|
||||
|
||||
//! Return a string representation from an OpenCL \a errorCode
|
||||
//! Returns a string representation from an OpenCL \a errorCode
|
||||
static QString errorText( const int errorCode );
|
||||
|
||||
/**
|
||||
* Build the program from \a source in the given \a context and depending on \a exeptionBehavior
|
||||
* Build the program from \a source in the given \a context and depending on \a exceptionBehavior
|
||||
* can throw or catch the exceptions
|
||||
* \return the built program
|
||||
*/
|
||||
@ -166,16 +183,16 @@ class CORE_EXPORT QgsOpenClUtils
|
||||
*/
|
||||
static cl::Context context();
|
||||
|
||||
//! Return the base path to OpenCL program directory
|
||||
//! Returns the base path to OpenCL program directory
|
||||
static QString sourcePath();
|
||||
|
||||
//! Set the base path to OpenCL program directory
|
||||
static void setSourcePath( const QString &value );
|
||||
|
||||
//! Return \a infoType information about the default device
|
||||
static QString defaultDeviceInfo( const Info infoType = Info::Name );
|
||||
//! Returns \a infoType information about the active (default) device
|
||||
static QString activeDeviceInfo( const Info infoType = Info::Name );
|
||||
|
||||
//! Return \a infoType information about the \a device
|
||||
//! Returns \a infoType information about the \a device
|
||||
static QString deviceInfo( const Info infoType, cl::Device device );
|
||||
|
||||
/**
|
||||
@ -188,23 +205,23 @@ class CORE_EXPORT QgsOpenClUtils
|
||||
|
||||
public:
|
||||
|
||||
explicit CPLAllocator( unsigned long size ): mMem( ( T * )CPLMalloc( sizeof( T ) * size ) ) { }
|
||||
explicit CPLAllocator( unsigned long size ): mMem( static_cast<T *>( CPLMalloc( sizeof( T ) * size ) ) ) { }
|
||||
|
||||
~CPLAllocator()
|
||||
{
|
||||
CPLFree( ( void * )mMem );
|
||||
CPLFree( static_cast<void *>( mMem ) );
|
||||
}
|
||||
|
||||
void reset( T *newData )
|
||||
{
|
||||
if ( mMem )
|
||||
CPLFree( ( void * )mMem );
|
||||
CPLFree( static_cast<void *>( mMem ) );
|
||||
mMem = newData;
|
||||
}
|
||||
|
||||
void reset( unsigned long size )
|
||||
{
|
||||
reset( ( T * )CPLMalloc( sizeof( T ) *size ) );
|
||||
reset( static_cast<T *>( CPLMalloc( sizeof( T ) *size ) ) );
|
||||
}
|
||||
|
||||
T &operator* ()
|
||||
@ -236,8 +253,29 @@ class CORE_EXPORT QgsOpenClUtils
|
||||
|
||||
|
||||
private:
|
||||
|
||||
QgsOpenClUtils();
|
||||
|
||||
/**
|
||||
* Activate a device identified by its \a preferredDeviceId by making it the default device
|
||||
* if the device does not exists or deviceId is empty, the first GPU device will be
|
||||
* activated, if a GPU device is not found, the first CPU device will be chosen instead.
|
||||
*
|
||||
* Called once by init() when OpenCL is used for the first time in a QGIS working session.
|
||||
*
|
||||
* \return true if the device could be found and activated. Return false if the device was already
|
||||
* the active one or if a device could not be activated.
|
||||
*
|
||||
* \see init()
|
||||
* \see available()
|
||||
*/
|
||||
static bool activate( const QString &preferredDeviceId = QString() );
|
||||
|
||||
/**
|
||||
* Initialize the OpenCL system by setting and activating the default device.
|
||||
*/
|
||||
static void init();
|
||||
|
||||
static bool sAvailable;
|
||||
static cl::Device sActiveDevice;
|
||||
static cl::Platform sDefaultPlatform;
|
||||
|
Loading…
x
Reference in New Issue
Block a user