Skip to content

Commit

Permalink
[opencl] Backports from master: manual merge
Browse files Browse the repository at this point in the history
  • Loading branch information
elpaso committed Dec 5, 2018
1 parent bb2b6a0 commit 4fd305c
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 26 deletions.
4 changes: 2 additions & 2 deletions src/analysis/raster/qgsninecellfilter.cpp
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
63 changes: 51 additions & 12 deletions src/core/qgsopenclutils.cpp
Expand Up @@ -39,7 +39,7 @@ 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 )
if ( platver.find( "OpenCL " ) != std::string::npos )
{
std::vector<cl::Device> _devices;
// Check for a device
Expand Down Expand Up @@ -217,7 +217,7 @@ 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 )
if ( platver.find( "OpenCL " ) != std::string::npos )
{
std::vector<cl::Device> devices;
// Search for a device
Expand All @@ -244,7 +244,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 @@ -259,7 +259,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_CPU )
{
// Got one!
plat = p;
Expand All @@ -271,7 +271,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 @@ -286,7 +286,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 All @@ -313,7 +313,7 @@ bool QgsOpenClUtils::activate( const QString &preferredDeviceId )
{
QgsMessageLog::logMessage( QObject::tr( "Error %1 searching for OpenCL device: %2" )
.arg( errorText( e.err() ), QString::fromStdString( e.what() ) ),
LOGMESSAGE_TAG, Qgis::Critical );
LOGMESSAGE_TAG, Qgis::Warning );
sAvailable = false;
}
return sAvailable;
Expand Down Expand Up @@ -496,6 +496,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 @@ -510,15 +531,33 @@ 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
// TODO: make this configurable
program.build( QStringLiteral( "-cl-std=CL1.1 -I%1" ).arg( sourcePath() ).toStdString().c_str() );
program = cl::Program( QgsOpenClUtils::context(), source.toStdString( ) );
// OpenCL version for compatibility with older hardware, but it's up to
// llvm to support latest CL versions
bool ok;
float version( QgsOpenClUtils::activePlatformVersion().toFloat( &ok ) );
if ( ok && version < 2.0f )
{
program.build( QStringLiteral( "-cl-std=CL%1 -I%2" )
.arg( QgsOpenClUtils::activePlatformVersion( ) )
.arg( sourcePath() ).toStdString().c_str() );
}
else
{
program.build( QStringLiteral( "-I%1" )
.arg( sourcePath() ).toStdString().c_str() );
}
}
catch ( cl::BuildError &e )
{
Expand Down
43 changes: 36 additions & 7 deletions src/core/qgsopenclutils.h
Expand Up @@ -19,12 +19,18 @@
#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

#include <QtGlobal>
#ifdef Q_OS_MAC
#define CL_HPP_MINIMUM_OPENCL_VERSION 120
#define CL_HPP_TARGET_OPENCL_VERSION 120
#define CL_TARGET_OPENCL_VERSION 120
#else
#define CL_USE_DEPRECATED_OPENCL_1_1_APIS
#define CL_HPP_TARGET_OPENCL_VERSION 220
#define CL_TARGET_OPENCL_VERSION 200
#endif

#include <CL/cl2.hpp>

#include "qgis_core.h"
Expand Down Expand Up @@ -134,6 +140,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 +184,28 @@ class CORE_EXPORT QgsOpenClUtils
//! Returns a string representation from an OpenCL \a errorCode
static QString errorText( const int errorCode );

/**
* Create an OpenCL command queue from the default context.
*
* This wrapper is required in order to prevent a crash when
* running on OpenCL platforms < 2
*/
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
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
5 changes: 2 additions & 3 deletions tests/src/core/testqgsopenclutils.cpp
Expand Up @@ -148,8 +148,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 +157,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

0 comments on commit 4fd305c

Please sign in to comment.