Skip to content

Commit

Permalink
[opencl] Support for platforms > 1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
elpaso committed Nov 30, 2018
1 parent 0af1ce4 commit 6176159
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 23 deletions.
4 changes: 2 additions & 2 deletions src/analysis/raster/qgsninecellfilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee

// Prepare context and queue
cl::Context ctx = QgsOpenClUtils::context();
cl::CommandQueue queue( ctx );
cl::CommandQueue queue = QgsOpenClUtils::commandQueue();

//keep only three scanlines in memory at a time, make room for initial and final nodata
QgsOpenClUtils::CPLAllocator<float> scanLine( xSize + 2 );
Expand Down Expand Up @@ -245,7 +245,7 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee
cl::Buffer resultLineBuffer( ctx, CL_MEM_WRITE_ONLY, inputSize, nullptr, nullptr );

// Create a program from the kernel source
cl::Program program( QgsOpenClUtils::buildProgram( ctx, source, QgsOpenClUtils::ExceptionBehavior::Throw ) );
cl::Program program( QgsOpenClUtils::buildProgram( source, QgsOpenClUtils::ExceptionBehavior::Throw ) );

// Create the OpenCL kernel
auto kernel = cl::KernelFunctor <
Expand Down
65 changes: 55 additions & 10 deletions src/core/qgsopenclutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ const std::vector<cl::Device> QgsOpenClUtils::devices()
{
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 )
// Check both versions 1 and 2
if ( platver.find( "OpenCL 1." ) != std::string::npos || platver.find( "OpenCL 2." ) != std::string::npos )
{
std::vector<cl::Device> _devices;
// Check for a device
Expand Down Expand Up @@ -166,6 +167,20 @@ cl::Device QgsOpenClUtils::activeDevice()
return sActiveDevice;
}

QString QgsOpenClUtils::activePlatformVersion()
{
QString version;
if ( QgsOpenClUtils::sDefaultPlatform() )
{
std::string platver = QgsOpenClUtils::sDefaultPlatform.getInfo<CL_PLATFORM_VERSION>();
if ( platver.find( "OpenCL " ) != std::string::npos )
{
version = QString::fromStdString( platver.substr( 7 ) ).split( ' ' ).first();
}
}
return version;
}

void QgsOpenClUtils::storePreferredDevice( const QString deviceId )
{
QgsSettings().setValue( SETTINGS_DEFAULT_DEVICE_KEY, deviceId, QgsSettings::Section::Core );
Expand Down Expand Up @@ -204,7 +219,8 @@ bool QgsOpenClUtils::activate( const QString &preferredDeviceId )
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 )
// Checks both versions 1 and 2
if ( platver.find( "OpenCL 1." ) != std::string::npos || platver.find( "OpenCL 2." ) != std::string::npos )
{
std::vector<cl::Device> devices;
// Search for a device
Expand All @@ -231,7 +247,7 @@ bool QgsOpenClUtils::activate( const QString &preferredDeviceId )
{
for ( const auto &_dev : devices )
{
if ( preferredDeviceId.isEmpty() && _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
{
// Got one!
plat = p;
Expand All @@ -246,7 +262,7 @@ bool QgsOpenClUtils::activate( const QString &preferredDeviceId )
{
for ( const auto &_dev : devices )
{
if ( preferredDeviceId.isEmpty() && _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
if ( _dev.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_GPU )
{
// Got one!
plat = p;
Expand All @@ -258,7 +274,7 @@ bool QgsOpenClUtils::activate( const QString &preferredDeviceId )
}
if ( ! deviceFound )
{
QgsMessageLog::logMessage( QObject::tr( "No OpenCL 1.x device could be found." ), LOGMESSAGE_TAG, Qgis::Warning );
QgsMessageLog::logMessage( QObject::tr( "No OpenCL device could be found." ), LOGMESSAGE_TAG, Qgis::Warning );
}
}
catch ( cl::Error &e )
Expand All @@ -273,7 +289,7 @@ bool QgsOpenClUtils::activate( const QString &preferredDeviceId )
}
if ( ! plat() )
{
QgsMessageLog::logMessage( QObject::tr( "No OpenCL 1.x platform found." ), LOGMESSAGE_TAG, Qgis::Warning );
QgsMessageLog::logMessage( QObject::tr( "No OpenCL platform found." ), LOGMESSAGE_TAG, Qgis::Warning );
sAvailable = false;
}
else
Expand Down Expand Up @@ -485,6 +501,27 @@ QString QgsOpenClUtils::errorText( const int errorCode )
}
}

cl::CommandQueue QgsOpenClUtils::commandQueue()
{
// Depending on the platform version, to avoid a crash
// we need to use the legacy calls to C API instead of the 2.0
// compatible C++ API.
cl::Context context( QgsOpenClUtils::context() );
if ( QgsOpenClUtils::activePlatformVersion().toFloat() >= 200 )
{
return cl::CommandQueue( context );
}
else // legacy
{
cl::Device device( QgsOpenClUtils::activeDevice() );
cl_command_queue_properties properties = 0;
Q_NOWARN_DEPRECATED_PUSH
cl_command_queue queue = clCreateCommandQueue( context(), device(), properties, nullptr );
Q_NOWARN_DEPRECATED_POP
return cl::CommandQueue( queue, true );
}
}

cl::Context QgsOpenClUtils::context()
{
static cl::Context context;
Expand All @@ -499,15 +536,23 @@ cl::Context QgsOpenClUtils::context()
return context;
}

cl::Program QgsOpenClUtils::buildProgram( const cl::Context &context, const QString &source, ExceptionBehavior exceptionBehavior )
cl::Program QgsOpenClUtils::buildProgram( const cl::Context &, const QString &source, ExceptionBehavior exceptionBehavior )
{
// Deprecated: ignore context and use default
return buildProgram( source, exceptionBehavior );
}

cl::Program QgsOpenClUtils::buildProgram( const QString &source, QgsOpenClUtils::ExceptionBehavior exceptionBehavior )
{
cl::Program program;
try
{
program = cl::Program( context, source.toStdString( ) );
// OpenCL 1.1 for compatibility with older hardware
program = cl::Program( QgsOpenClUtils::context(), source.toStdString( ) );
// OpenCL version for compatibility with older hardware
// TODO: make this configurable
program.build( QStringLiteral( "-cl-std=CL1.1 -I%1" ).arg( sourcePath() ).toStdString().c_str() );
program.build( QStringLiteral( "-cl-std=CL%1 -I%2" )
.arg( QgsOpenClUtils::activePlatformVersion( ) )
.arg( sourcePath() ).toStdString().c_str() );
}
catch ( cl::BuildError &e )
{
Expand Down
28 changes: 21 additions & 7 deletions src/core/qgsopenclutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@
#define SIP_NO_FILE

#define CL_HPP_ENABLE_EXCEPTIONS
// Set target version to 1.10 because it's the best compromise
// between features and compatibility with "older" graphics
// cards
#define CL_HPP_MINIMUM_OPENCL_VERSION 110
#define CL_HPP_TARGET_OPENCL_VERSION 110
#define CL_TARGET_OPENCL_VERSION 110
//#define CL_HPP_MINIMUM_OPENCL_VERSION 110
#define CL_USE_DEPRECATED_OPENCL_1_1_APIS
#define CL_HPP_TARGET_OPENCL_VERSION 200
#include <CL/cl2.hpp>

#include "qgis_core.h"
Expand Down Expand Up @@ -134,6 +131,13 @@ class CORE_EXPORT QgsOpenClUtils
*/
static cl::Device activeDevice( );

/**
* Returns the active platform OpenCL version string (e.g. 1.1, 2.0 etc.)
* or a blank string if there is no active platform.
* \since QGIS 3.6
*/
static QString activePlatformVersion( );

//! Store in the settings the preferred \a deviceId device identifier
static void storePreferredDevice( const QString deviceId );

Expand Down Expand Up @@ -171,12 +175,22 @@ class CORE_EXPORT QgsOpenClUtils
//! Returns a string representation from an OpenCL \a errorCode
static QString errorText( const int errorCode );

static cl::CommandQueue commandQueue();

/**
* 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
* \deprecated since QGIS 3.6
*/
static cl::Program buildProgram( const cl::Context &context, const QString &source, ExceptionBehavior exceptionBehavior = Catch );
Q_DECL_DEPRECATED static cl::Program buildProgram( const cl::Context &context, const QString &source, ExceptionBehavior exceptionBehavior = Catch );

/**
* Build the program from \a source, depending on \a exceptionBehavior can throw or catch the exceptions
* \return the built program
*/
static cl::Program buildProgram( const QString &source, ExceptionBehavior exceptionBehavior = Catch );


/**
* Context factory
Expand Down
4 changes: 2 additions & 2 deletions src/core/raster/qgshillshaderenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ QgsRasterBlock *QgsHillshadeRenderer::block( int bandNo, const QgsRectangle &ext
// Note: output block is not 2px wider and it is an image
// Prepare context and queue
cl::Context ctx = QgsOpenClUtils::context();
cl::CommandQueue queue( ctx );
cl::CommandQueue queue = QgsOpenClUtils::commandQueue();

// Cast to float (because double just crashes on some GPUs)
std::vector<float> rasterParams;
Expand Down Expand Up @@ -250,7 +250,7 @@ QgsRasterBlock *QgsHillshadeRenderer::block( int bandNo, const QgsRectangle &ext
std::call_once( programBuilt, [ = ]()
{
// Create a program from the kernel source
program = QgsOpenClUtils::buildProgram( ctx, source, QgsOpenClUtils::ExceptionBehavior::Throw );
program = QgsOpenClUtils::buildProgram( source, QgsOpenClUtils::ExceptionBehavior::Throw );
} );

// Disable program cache when developing and testing cl program
Expand Down
12 changes: 10 additions & 2 deletions tests/src/core/testqgsopenclutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class TestQgsOpenClUtils: public QObject
void testProgramSource();
void testContext();
void testDevices();
void testActiveDeviceVersion();

// For benchmarking performance testing
void testHillshadeCPU();
Expand Down Expand Up @@ -149,7 +150,7 @@ void TestQgsOpenClUtils::_testMakeRunProgram()
QVERIFY( err == 0 );

cl::Context ctx = QgsOpenClUtils::context();
cl::CommandQueue queue( ctx );
cl::CommandQueue queue = QgsOpenClUtils::commandQueue();

std::vector<float> a_vec = {1, 10, 100};
std::vector<float> b_vec = {1, 10, 100};
Expand All @@ -158,7 +159,7 @@ void TestQgsOpenClUtils::_testMakeRunProgram()
cl::Buffer b_buf( queue, b_vec.begin(), b_vec.end(), true );
cl::Buffer c_buf( queue, c_vec.begin(), c_vec.end(), false );

cl::Program program = QgsOpenClUtils::buildProgram( ctx, QString::fromStdString( source() ) );
cl::Program program = QgsOpenClUtils::buildProgram( QString::fromStdString( source() ) );

auto kernel =
cl::KernelFunctor <
Expand Down Expand Up @@ -207,6 +208,13 @@ void TestQgsOpenClUtils::testDevices()
qDebug() << QgsOpenClUtils::deviceInfo( QgsOpenClUtils::Info::Type, _devices.at( 0 ) );
}

void TestQgsOpenClUtils::testActiveDeviceVersion()
{
QString version = QgsOpenClUtils::activePlatformVersion();
qDebug() << "OPENCL VERSION" << version;
QVERIFY( version.length() == 3 );
}

void TestQgsOpenClUtils::_testMakeHillshade( const int loops )
{
for ( int i = 0 ; i < loops; i++ )
Expand Down

0 comments on commit 6176159

Please sign in to comment.