21#include <cpl_string.h>
31using namespace Qt::StringLiterals;
56 if ( !source.isEmpty() )
60 QgsDebugMsgLevel( u
"Running OpenCL program: %1"_s.arg( openClProgramBaseName() ), 2 );
61 return processRasterGPU( source, feedback );
63 catch ( cl::Error &e )
65 const QString err = QObject::tr(
"Error running OpenCL program: %1 - %2" ).arg( e.what(),
QgsOpenClUtils::errorText( e.err() ) );
72 const QString err = QObject::tr(
"Error loading OpenCL program sources" );
79 return processRasterCPU( feedback );
85 return processRasterCPU( feedback );
94 nCellsX = GDALGetRasterXSize( inputDataset.get() );
95 nCellsY = GDALGetRasterYSize( inputDataset.get() );
98 if ( GDALGetRasterCount( inputDataset.get() ) < 1 )
106GDALDriverH QgsNineCellFilter::openOutputDriver()
109 GDALDriverH outputDriver = GDALGetDriverByName(
mOutputFormat.toLocal8Bit().data() );
131 const int xSize = GDALGetRasterXSize( inputDataset );
132 const int ySize = GDALGetRasterYSize( inputDataset );
137 CSLDestroy( papszOptions );
138 if ( !outputDataset )
140 return outputDataset;
144 double geotransform[6];
145 if ( GDALGetGeoTransform( inputDataset, geotransform ) != CE_None )
149 GDALSetGeoTransform( outputDataset.get(), geotransform );
163 const char *projection = GDALGetProjectionRef( inputDataset );
164 GDALSetProjection( outputDataset.get(), projection );
166 return outputDataset;
184 GDALDriverH outputDriver = openOutputDriver();
191 if ( !outputDataset )
197 GDALRasterBandH rasterBand = GDALGetRasterBand( inputDataset.get(), 1 );
204 GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset.get(), 1 );
205 if ( !outputRasterBand )
217#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 13, 0 )
218 const bool hasReportsDuringClose = GDALDatasetGetCloseReportsProgress( outputDataset.get() );
219 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
221 constexpr double maxProgressDuringBlockWriting = 100.0;
229 QgsOpenClUtils::CPLAllocator<float> scanLine( xSize + 2 );
230 QgsOpenClUtils::CPLAllocator<float> resultLine( xSize );
233 std::vector<float> rasterParams;
243 addExtraRasterParams( rasterParams );
245 const std::size_t bufferSize(
sizeof(
float ) * ( xSize + 2 ) );
246 const std::size_t inputSize(
sizeof(
float ) * ( xSize ) );
248 cl::Buffer rasterParamsBuffer( queue, rasterParams.begin(), rasterParams.end(),
true,
false,
nullptr );
249 cl::Buffer scanLine1Buffer( ctx, CL_MEM_READ_ONLY, bufferSize,
nullptr,
nullptr );
250 cl::Buffer scanLine2Buffer( ctx, CL_MEM_READ_ONLY, bufferSize,
nullptr,
nullptr );
251 cl::Buffer scanLine3Buffer( ctx, CL_MEM_READ_ONLY, bufferSize,
nullptr,
nullptr );
252 cl::Buffer *scanLineBuffer[3] = { &scanLine1Buffer, &scanLine2Buffer, &scanLine3Buffer };
253 cl::Buffer resultLineBuffer( ctx, CL_MEM_WRITE_ONLY, inputSize,
nullptr,
nullptr );
259 auto kernel = cl::KernelFunctor<
264 cl::Buffer &>( program,
"processNineCellWindow" );
267 std::vector<int> rowIndex = { 0, 1, 2 };
270 for (
int i = 0; i < ySize; ++i )
279 feedback->
setProgress( maxProgressDuringBlockWriting *
static_cast<double>( i ) / ySize );
286 for (
int a = 0; a < xSize + 2; ++a )
290 queue.enqueueWriteBuffer( scanLine1Buffer, CL_TRUE, 0, bufferSize, scanLine.get() );
293 if ( GDALRasterIO( rasterBand, GF_Read, 0, i, xSize, 1, &scanLine[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
297 queue.enqueueWriteBuffer( scanLine2Buffer, CL_TRUE, 0, bufferSize, scanLine.get() );
300 if ( GDALRasterIO( rasterBand, GF_Read, 0, i + 1, xSize, 1, &scanLine[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
304 queue.enqueueWriteBuffer( scanLine3Buffer, CL_TRUE, 0, bufferSize, scanLine.get() );
310 if ( i == ySize - 1 )
312 for (
int a = 0; a < xSize + 2; ++a )
316 queue.enqueueWriteBuffer( *scanLineBuffer[rowIndex[2]], CL_TRUE, 0, bufferSize, scanLine.get() );
321 if ( GDALRasterIO( rasterBand, GF_Read, 0, i + 1, xSize, 1, &scanLine[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
325 queue.enqueueWriteBuffer( *scanLineBuffer[rowIndex[2]], CL_TRUE, 0, bufferSize, scanLine.get() );
329 kernel( cl::EnqueueArgs( queue, cl::NDRange( xSize ) ), *scanLineBuffer[rowIndex[0]], *scanLineBuffer[rowIndex[1]], *scanLineBuffer[rowIndex[2]], resultLineBuffer, rasterParamsBuffer );
331 queue.enqueueReadBuffer( resultLineBuffer, CL_TRUE, 0, inputSize, resultLine.get() );
333 if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, xSize, 1, resultLine.get(), xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
337 std::rotate( rowIndex.begin(), rowIndex.begin() + 1, rowIndex.end() );
346#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 13, 0 )
347 else if ( hasReportsDuringClose && feedback )
349 QgsGdalProgressAdapter progress( feedback, maxProgressDuringBlockWriting );
350 if ( GDALDatasetRunCloseWithoutDestroyingEx(
378 GDALDriverH outputDriver = openOutputDriver();
385 if ( !outputDataset )
390#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 13, 0 )
391 const bool hasReportsDuringClose = GDALDatasetGetCloseReportsProgress( outputDataset.get() );
392 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
394 constexpr double maxProgressDuringBlockWriting = 100.0;
398 GDALRasterBandH rasterBand = GDALGetRasterBand( inputDataset.get(), 1 );
405 GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset.get(), 1 );
406 if ( !outputRasterBand )
419 const std::size_t bufferSize(
sizeof(
float ) * ( xSize + 2 ) );
420 float *scanLine1 = (
float * ) CPLMalloc( bufferSize );
421 float *scanLine2 = (
float * ) CPLMalloc( bufferSize );
422 float *scanLine3 = (
float * ) CPLMalloc( bufferSize );
424 float *resultLine = (
float * ) CPLMalloc(
sizeof(
float ) * xSize );
427 for (
int yIndex = 0; yIndex < ySize; ++yIndex )
436 feedback->
setProgress( maxProgressDuringBlockWriting *
static_cast<double>( yIndex ) / ySize );
442 for (
int a = 0; a < xSize + 2; ++a )
447 if ( GDALRasterIO( rasterBand, GF_Read, 0, 0, xSize, 1, &scanLine2[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
455 CPLFree( scanLine1 );
456 scanLine1 = scanLine2;
457 scanLine2 = scanLine3;
458 scanLine3 = (
float * ) CPLMalloc( bufferSize );
462 if ( yIndex == ySize - 1 )
464 for (
int a = 0; a < xSize + 2; ++a )
471 if ( GDALRasterIO( rasterBand, GF_Read, 0, yIndex + 1, xSize, 1, &scanLine3[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
483 for (
int xIndex = 0; xIndex < xSize; ++xIndex )
486 resultLine[xIndex] =
processNineCellWindow( &scanLine1[xIndex], &scanLine1[xIndex + 1], &scanLine1[xIndex + 2], &scanLine2[xIndex], &scanLine2[xIndex + 1], &scanLine2[xIndex + 2], &scanLine3[xIndex], &scanLine3[xIndex + 1], &scanLine3[xIndex + 2] );
489 if ( GDALRasterIO( outputRasterBand, GF_Write, 0, yIndex, xSize, 1, resultLine, xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
495 CPLFree( resultLine );
496 CPLFree( scanLine1 );
497 CPLFree( scanLine2 );
498 CPLFree( scanLine3 );
506#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 13, 0 )
507 else if ( hasReportsDuringClose && feedback )
509 QgsGdalProgressAdapter progress( feedback, maxProgressDuringBlockWriting );
510 if ( GDALDatasetRunCloseWithoutDestroyingEx(
@ Critical
Critical/error message.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
static int CPL_STDCALL progressCallback(double dfComplete, const char *pszMessage, void *pProgressArg)
GDAL progress callback.
static bool supportsRasterCreate(GDALDriverH driver)
Reads whether a driver supports GDALCreate() for raster purposes.
static char ** papszFromStringList(const QStringList &list)
Helper function.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
QStringList mCreationOptions
virtual float processNineCellWindow(float *x11, float *x21, float *x31, float *x12, float *x22, float *x32, float *x13, float *x23, float *x33)=0
Calculates output value from nine input values.
Result
Result of the calculation.
@ Canceled
User canceled calculation.
@ InputLayerError
Error reading input file.
@ RasterSizeError
Raster height is too small (need at least 3 rows).
@ Success
Operation completed successfully.
@ CreateOutputError
Error creating output file.
@ DriverError
Could not open the driver for the specified format.
@ InputBandError
Error reading input raster band.
@ OutputBandError
Error reading output raster band.
QgsNineCellFilter(const QString &inputFile, const QString &outputFile, const QString &outputFormat)
Constructor that takes input file, output file and output format (GDAL string).
double mOutputNodataValue
The nodata value of the output layer.
double mInputNodataValue
The nodata value of the input layer.
Result processRaster(QgsFeedback *feedback=nullptr)
Starts the calculation, reads from mInputFile and stores the result in mOutputFile.
double mZFactor
Scale factor for z-value if x-/y- units are different to z-units (111120 for degree->meters and 37040...
static Q_DECL_DEPRECATED cl::Program buildProgram(const cl::Context &context, const QString &source, ExceptionBehavior exceptionBehavior=Catch)
Build the program from source in the given context and depending on exceptionBehavior can throw or ca...
static cl::Context context()
Context factory.
static bool enabled()
Returns true if OpenCL is enabled in the user settings.
static bool available()
Checks whether a suitable OpenCL platform and device is available on this system and initialize the Q...
static QString errorText(const int errorCode)
Returns a string representation from an OpenCL errorCode.
static cl::CommandQueue commandQueue()
Create an OpenCL command queue from the default context.
static QString sourceFromBaseName(const QString &baseName)
Returns the full path to a an OpenCL source file from the baseName ('.cl' extension is automatically ...
@ Throw
Write errors in the message log and re-throw exceptions.
static QLatin1String LOGMESSAGE_TAG
OpenCL string for message logs.
Custom exception class for processing related exceptions.
void CORE_EXPORT fast_delete_and_close(dataset_unique_ptr &dataset, GDALDriverH driver, const QString &path)
Performs a fast close of an unwanted GDAL dataset handle by deleting the underlying data store.
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)