diff --git a/CMakeLists.txt b/CMakeLists.txt index ab6f236894d..1c99d9f20af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/src/analysis/raster/qgsninecellfilter.cpp b/src/analysis/raster/qgsninecellfilter.cpp index 5a9d8374dd0..7a3a9d2fc7c 100644 --- a/src/analysis/raster/qgsninecellfilter.cpp +++ b/src/analysis/raster/qgsninecellfilter.cpp @@ -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 @@ -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 ) @@ -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 ) { @@ -224,21 +226,25 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee // Cast to float (because double just crashes on some GPUs) std::vector 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 ) ); @@ -252,6 +258,9 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee cl::Buffer & > ( program, "processNineCellWindow" ); + // Rotate buffer index + std::vector 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 ) { @@ -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" ); } @@ -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 @@ -310,7 +317,7 @@ 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 } } @@ -318,22 +325,22 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee 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) @@ -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 ) { @@ -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; diff --git a/src/analysis/raster/qgsninecellfilter.h b/src/analysis/raster/qgsninecellfilter.h index 15d6c877833..b17d4856c17 100644 --- a/src/analysis/raster/qgsninecellfilter.h +++ b/src/analysis/raster/qgsninecellfilter.h @@ -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; } @@ -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; @@ -85,9 +99,8 @@ 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 ); @@ -95,12 +108,17 @@ class ANALYSIS_EXPORT QgsNineCellFilter /** * \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 ¶ms ) { Q_UNUSED( params );