Skip to content

Commit

Permalink
OpenCL POC 1
Browse files Browse the repository at this point in the history
  • Loading branch information
elpaso committed Aug 8, 2018
1 parent a1a09d7 commit 51d1bb3
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 35 deletions.
7 changes: 7 additions & 0 deletions CMakeLists.txt
Expand Up @@ -34,9 +34,16 @@ option(USE_OPENCL "Use OpenCL" ON)
if (USE_OPENCL)
FIND_PACKAGE(OpenCL)
if(${OpenCL_FOUND})
<<<<<<< a1a09d75e627b0f085c5a1177db5d58374ca6f44
SET(HAVE_OPENCL TRUE)
else(${OpenCL_FOUND})
MESSAGE(STATUS "Couldn't find OpenCL: support DISABLED")
=======
SET (USE_OPENCL TRUE CACHE BOOL "Use OpenCL")
IF(USE_OPENCL)
SET(HAVE_OPENCL TRUE)
ENDIF(USE_OPENCL)
>>>>>>> OpenCL POC 1
endif(${OpenCL_FOUND})
endif(USE_OPENCL)

Expand Down
59 changes: 34 additions & 25 deletions src/analysis/raster/qgsninecellfilter.cpp
Expand Up @@ -41,6 +41,7 @@ QgsNineCellFilter::QgsNineCellFilter( const QString &inputFile, const QString &o

}

// TODO: return an anum instead of an int
int QgsNineCellFilter::processRaster( QgsFeedback *feedback )
{
#ifdef HAVE_OPENCL
Expand All @@ -52,8 +53,8 @@ int QgsNineCellFilter::processRaster( QgsFeedback *feedback )
{
try
{
QgsMessageLog::logMessage( QObject::tr( "Running OpenCL program: %1" )
.arg( openClProgramBaseName( ) ), QgsOpenClUtils::LOGMESSAGE_TAG, Qgis::Info );
QgsDebugMsg( QObject::tr( "Running OpenCL program: %1" )
.arg( openClProgramBaseName( ) ), QgsOpenClUtils::LOGMESSAGE_TAG, Qgis::Info );
return processRasterGPU( source, feedback );
}
catch ( cl::Error &e )
Expand Down Expand Up @@ -165,6 +166,7 @@ gdal::dataset_unique_ptr QgsNineCellFilter::openOutputFile( GDALDatasetH inputDa

#ifdef HAVE_OPENCL

// TODO: return an anum instead of an int
int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *feedback )
{

Expand Down Expand Up @@ -224,21 +226,25 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee
// Cast to float (because double just crashes on some GPUs)
std::vector<float> rasterParams;

rasterParams.push_back( mInputNodataValue );
rasterParams.push_back( mOutputNodataValue );
rasterParams.push_back( mZFactor );
rasterParams.push_back( mCellSizeX );
rasterParams.push_back( mCellSizeY );
rasterParams.push_back( mInputNodataValue ); // 0
rasterParams.push_back( mOutputNodataValue ); // 1
rasterParams.push_back( mZFactor ); // 2
rasterParams.push_back( mCellSizeX ); // 3
rasterParams.push_back( mCellSizeY ); // 4

// Allow subclasses to add extra params needed for computation:
// used to pass additional args to opencl program
addExtraRasterParams( rasterParams );

std::size_t bufferSize( sizeof( float ) * ( xSize + 2 ) );
std::size_t inputSize( sizeof( float ) * ( xSize ) );

cl::Buffer rasterParamsBuffer( queue, rasterParams.begin(), rasterParams.end(), true, false, nullptr );
cl::Buffer scanLine1Buffer( ctx, CL_MEM_READ_ONLY, bufferSize, nullptr, nullptr );
cl::Buffer scanLine2Buffer( ctx, CL_MEM_READ_ONLY, bufferSize, nullptr, nullptr );
cl::Buffer scanLine3Buffer( ctx, CL_MEM_READ_ONLY, bufferSize, nullptr, nullptr );
cl::Buffer resultLineBuffer( ctx, CL_MEM_WRITE_ONLY, sizeof( float ) * xSize, nullptr, nullptr );
cl::Buffer *scanLineBuffer[3] = {&scanLine1Buffer, &scanLine2Buffer, &scanLine3Buffer};
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 ) );
Expand All @@ -252,6 +258,9 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee
cl::Buffer &
> ( program, "processNineCellWindow" );

// Rotate buffer index
std::vector<int> rowIndex = {0, 1, 2};

// values outside the layer extent (if the 3x3 window is on the border) are sent to the processing method as (input) nodata values
for ( int i = 0; i < ySize; ++i )
{
Expand All @@ -267,22 +276,23 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee

if ( i == 0 )
{
// Fill scanline 1 with (input) nodata for the values above the first row and feed scanline2 with the first row
// Fill scanline 1 with (input) nodata for the values above the first row and
// feed scanline2 with the first actual data row
for ( int a = 0; a < xSize + 2 ; ++a )
{
scanLine[a] = mInputNodataValue;
}
queue.enqueueWriteBuffer( scanLine1Buffer, CL_TRUE, 0, bufferSize, scanLine.get() );

// Read scanline2
if ( GDALRasterIO( rasterBand, GF_Read, 0, 0, xSize, 1, &scanLine[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
// Read scanline2: first real raster row
if ( GDALRasterIO( rasterBand, GF_Read, 0, i, xSize, 1, &scanLine[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
{
QgsDebugMsg( "Raster IO Error" );
}
queue.enqueueWriteBuffer( scanLine2Buffer, CL_TRUE, 0, bufferSize, scanLine.get() );

// Read scanline3
if ( GDALRasterIO( rasterBand, GF_Read, 0, 0, xSize, 1, &scanLine[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
// Read scanline3: second real raster row
if ( GDALRasterIO( rasterBand, GF_Read, 0, i + 1, xSize, 1, &scanLine[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
{
QgsDebugMsg( "Raster IO Error" );
}
Expand All @@ -291,17 +301,14 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee
else
{
// Normally fetch only scanLine3 and move forward one row
queue.enqueueCopyBuffer( scanLine2Buffer, scanLine1Buffer, 0, 0, bufferSize, nullptr, nullptr );
queue.enqueueCopyBuffer( scanLine3Buffer, scanLine2Buffer, 0, 0, bufferSize, nullptr, nullptr );

// Read scanline 3
// Read scanline 3, fill the last row with nodata values if it's the last iteration
if ( i == ySize - 1 ) //fill the row below the bottom with nodata values
{
for ( int a = 0; a < xSize + 2; ++a )
{
scanLine[a] = mInputNodataValue;
}
queue.enqueueWriteBuffer( scanLine3Buffer, CL_TRUE, 0, bufferSize, scanLine.get() ); // row 0
queue.enqueueWriteBuffer( *scanLineBuffer[rowIndex[2]], CL_TRUE, 0, bufferSize, scanLine.get() ); // row 0
}
else // Read line i + 1 and put it into scanline 3
// Overwrite from input, skip first and last
Expand All @@ -310,30 +317,30 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee
{
QgsDebugMsg( "Raster IO Error" );
}
queue.enqueueWriteBuffer( scanLine3Buffer, CL_TRUE, 0, bufferSize, scanLine.get() ); // row 0
queue.enqueueWriteBuffer( *scanLineBuffer[rowIndex[2]], CL_TRUE, 0, bufferSize, scanLine.get() ); // row 0
}
}

kernel( cl::EnqueueArgs(
queue,
cl::NDRange( xSize )
),
scanLine1Buffer,
scanLine2Buffer,
scanLine3Buffer,
*scanLineBuffer[rowIndex[0]],
*scanLineBuffer[rowIndex[1]],
*scanLineBuffer[rowIndex[2]],
resultLineBuffer,
rasterParamsBuffer
);

queue.enqueueReadBuffer( resultLineBuffer, CL_TRUE, 0, xSize * sizeof( float ), resultLine.get() );
queue.enqueueReadBuffer( resultLineBuffer, CL_TRUE, 0, inputSize, resultLine.get() );

if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, xSize, 1, resultLine.get(), xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
{
QgsDebugMsg( "Raster IO Error" );
}
std::rotate( rowIndex.begin(), rowIndex.begin() + 1, rowIndex.end() );
}


if ( feedback && feedback->isCanceled() )
{
//delete the dataset without closing (because it is faster)
Expand All @@ -344,6 +351,8 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee
}
#endif


// TODO: return an anum instead of an int
int QgsNineCellFilter::processRasterCPU( QgsFeedback *feedback )
{

Expand Down Expand Up @@ -450,7 +459,7 @@ int QgsNineCellFilter::processRasterCPU( QgsFeedback *feedback )
QgsDebugMsg( "Raster IO Error" );
}
}
// Set first and last extra colums to nodata
// Set first and last extra columns to nodata
scanLine1[0] = scanLine1[xSize + 1] = mInputNodataValue;
scanLine2[0] = scanLine2[xSize + 1] = mInputNodataValue;
scanLine3[0] = scanLine3[xSize + 1] = mInputNodataValue;
Expand Down
38 changes: 28 additions & 10 deletions src/analysis/raster/qgsninecellfilter.h
Expand Up @@ -40,10 +40,9 @@ class ANALYSIS_EXPORT QgsNineCellFilter

/**
* Starts the calculation, reads from mInputFile and stores the result in mOutputFile
\param feedback feedback object that receives update and that is checked for cancelation.
\returns 0 in case of success
TODO: return an enum
*/
* \param feedback feedback object that receives update and that is checked for cancelation.
* \returns 0 in case of success
*/
int processRaster( QgsFeedback *feedback = nullptr );

double cellSizeX() const { return mCellSizeX; }
Expand All @@ -60,8 +59,23 @@ class ANALYSIS_EXPORT QgsNineCellFilter
void setOutputNodataValue( double value ) { mOutputNodataValue = value; }

/**
* Calculates output value from nine input values. The input values and the output value can be equal to the
nodata value if not present or outside of the border. Must be implemented by subclasses*/
* Calculates output value from nine input values. The input values and the output
* value can be equal to the nodata value if not present or outside of the border.
* Must be implemented by subclasses.
*
* First index of the input cell is the row, second index is the column
*
* @param x11 surrounding cell top left
* @param x21 surrounding cell central left
* @param x31 surrounding cell bottom left
* @param x12 surrounding cell top central
* @param x22 the central cell for which the value will be calculated
* @param x32 surrounding cell bottom central
* @param x13 surrounding cell top right
* @param x23 surrounding cell central right
* @param x33 surrounding cell bottom right
* @return the calculated cell value for the central cell x22
*/
virtual float processNineCellWindow( float *x11, float *x21, float *x31,
float *x12, float *x22, float *x32,
float *x13, float *x23, float *x33 ) = 0;
Expand All @@ -85,22 +99,26 @@ class ANALYSIS_EXPORT QgsNineCellFilter

/**
* \brief processRasterCPU executes the computation on the CPU
* \param feedback
* \param feedback instance of QgsFeedback, to allow for progress monitoring and cancelation
* \return an opaque integer for error codes: 0 in case of success
* TODO: return an enum
*/
int processRasterCPU( QgsFeedback *feedback = nullptr );

#ifdef HAVE_OPENCL

/**
* \brief processRasterGPU executes the computation on the GPU
* \param feedback
* \param source path to the OpenCL source file
* \param feedback instance of QgsFeedback, to allow for progress monitoring and cancelation
* \return an opaque integer for error codes: 0 in case of success
* TODO: return an enum
*/
int processRasterGPU( const QString &source, QgsFeedback *feedback = nullptr );

/**
* \brief addExtraRasterParams allow derived classes to add parameters needed
* by OpenCL program
* \param params vector of parameters passed to OpenCL algorithm
*/
virtual void addExtraRasterParams( std::vector<float> &params )
{
Q_UNUSED( params );
Expand Down

0 comments on commit 51d1bb3

Please sign in to comment.