21#include <cpl_string.h>
31using namespace Qt::StringLiterals;
55 if ( !source.isEmpty() )
59 QgsDebugMsgLevel( u
"Running OpenCL program: %1"_s.arg( openClProgramBaseName() ), 2 );
60 return processRasterGPU( source, feedback );
62 catch ( cl::Error &e )
64 const QString err = QObject::tr(
"Error running OpenCL program: %1 - %2" ).arg( e.what(),
QgsOpenClUtils::errorText( e.err() ) );
71 const QString err = QObject::tr(
"Error loading OpenCL program sources" );
78 return processRasterCPU( feedback );
84 return processRasterCPU( feedback );
93 nCellsX = GDALGetRasterXSize( inputDataset.get() );
94 nCellsY = GDALGetRasterYSize( inputDataset.get() );
97 if ( GDALGetRasterCount( inputDataset.get() ) < 1 )
105GDALDriverH QgsNineCellFilter::openOutputDriver()
108 GDALDriverH outputDriver = GDALGetDriverByName(
mOutputFormat.toLocal8Bit().data() );
130 const int xSize = GDALGetRasterXSize( inputDataset );
131 const int ySize = GDALGetRasterYSize( inputDataset );
136 CSLDestroy( papszOptions );
137 if ( !outputDataset )
139 return outputDataset;
143 double geotransform[6];
144 if ( GDALGetGeoTransform( inputDataset, geotransform ) != CE_None )
148 GDALSetGeoTransform( outputDataset.get(), geotransform );
162 const char *projection = GDALGetProjectionRef( inputDataset );
163 GDALSetProjection( outputDataset.get(), projection );
165 return outputDataset;
183 GDALDriverH outputDriver = openOutputDriver();
190 if ( !outputDataset )
196 GDALRasterBandH rasterBand = GDALGetRasterBand( inputDataset.get(), 1 );
203 GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset.get(), 1 );
204 if ( !outputRasterBand )
216#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 13, 0 )
217 const bool hasReportsDuringClose = GDALDatasetGetCloseReportsProgress( outputDataset.get() );
218 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
220 constexpr double maxProgressDuringBlockWriting = 100.0;
228 QgsOpenClUtils::CPLAllocator<float> scanLine( xSize + 2 );
229 QgsOpenClUtils::CPLAllocator<float> resultLine( xSize );
232 std::vector<float> rasterParams;
242 addExtraRasterParams( rasterParams );
244 const std::size_t bufferSize(
sizeof(
float ) * ( xSize + 2 ) );
245 const std::size_t inputSize(
sizeof(
float ) * ( xSize ) );
247 cl::Buffer rasterParamsBuffer( queue, rasterParams.begin(), rasterParams.end(),
true,
false,
nullptr );
248 cl::Buffer scanLine1Buffer( ctx, CL_MEM_READ_ONLY, bufferSize,
nullptr,
nullptr );
249 cl::Buffer scanLine2Buffer( ctx, CL_MEM_READ_ONLY, bufferSize,
nullptr,
nullptr );
250 cl::Buffer scanLine3Buffer( ctx, CL_MEM_READ_ONLY, bufferSize,
nullptr,
nullptr );
251 cl::Buffer *scanLineBuffer[3] = { &scanLine1Buffer, &scanLine2Buffer, &scanLine3Buffer };
252 cl::Buffer resultLineBuffer( ctx, CL_MEM_WRITE_ONLY, inputSize,
nullptr,
nullptr );
258 auto kernel = cl::KernelFunctor< cl::Buffer &, cl::Buffer &, cl::Buffer &, cl::Buffer &, cl::Buffer &>( program,
"processNineCellWindow" );
261 std::vector<int> rowIndex = { 0, 1, 2 };
264 for (
int i = 0; i < ySize; ++i )
273 feedback->
setProgress( maxProgressDuringBlockWriting *
static_cast<double>( i ) / ySize );
280 for (
int a = 0; a < xSize + 2; ++a )
284 queue.enqueueWriteBuffer( scanLine1Buffer, CL_TRUE, 0, bufferSize, scanLine.get() );
287 if ( GDALRasterIO( rasterBand, GF_Read, 0, i, xSize, 1, &scanLine[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
291 queue.enqueueWriteBuffer( scanLine2Buffer, CL_TRUE, 0, bufferSize, scanLine.get() );
294 if ( GDALRasterIO( rasterBand, GF_Read, 0, i + 1, xSize, 1, &scanLine[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
298 queue.enqueueWriteBuffer( scanLine3Buffer, CL_TRUE, 0, bufferSize, scanLine.get() );
304 if ( i == ySize - 1 )
306 for (
int a = 0; a < xSize + 2; ++a )
310 queue.enqueueWriteBuffer( *scanLineBuffer[rowIndex[2]], CL_TRUE, 0, bufferSize, scanLine.get() );
315 if ( GDALRasterIO( rasterBand, GF_Read, 0, i + 1, xSize, 1, &scanLine[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
319 queue.enqueueWriteBuffer( *scanLineBuffer[rowIndex[2]], CL_TRUE, 0, bufferSize, scanLine.get() );
323 kernel( cl::EnqueueArgs( queue, cl::NDRange( xSize ) ), *scanLineBuffer[rowIndex[0]], *scanLineBuffer[rowIndex[1]], *scanLineBuffer[rowIndex[2]], resultLineBuffer, rasterParamsBuffer );
325 queue.enqueueReadBuffer( resultLineBuffer, CL_TRUE, 0, inputSize, resultLine.get() );
327 if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, xSize, 1, resultLine.get(), xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
331 std::rotate( rowIndex.begin(), rowIndex.begin() + 1, rowIndex.end() );
340#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 13, 0 )
341 else if ( hasReportsDuringClose && feedback )
343 QgsGdalProgressAdapter progress( feedback, maxProgressDuringBlockWriting );
369 GDALDriverH outputDriver = openOutputDriver();
376 if ( !outputDataset )
381#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 13, 0 )
382 const bool hasReportsDuringClose = GDALDatasetGetCloseReportsProgress( outputDataset.get() );
383 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
385 constexpr double maxProgressDuringBlockWriting = 100.0;
389 GDALRasterBandH rasterBand = GDALGetRasterBand( inputDataset.get(), 1 );
396 GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset.get(), 1 );
397 if ( !outputRasterBand )
410 const std::size_t bufferSize(
sizeof(
float ) * ( xSize + 2 ) );
411 float *scanLine1 = (
float * ) CPLMalloc( bufferSize );
412 float *scanLine2 = (
float * ) CPLMalloc( bufferSize );
413 float *scanLine3 = (
float * ) CPLMalloc( bufferSize );
415 float *resultLine = (
float * ) CPLMalloc(
sizeof(
float ) * xSize );
418 for (
int yIndex = 0; yIndex < ySize; ++yIndex )
427 feedback->
setProgress( maxProgressDuringBlockWriting *
static_cast<double>( yIndex ) / ySize );
433 for (
int a = 0; a < xSize + 2; ++a )
438 if ( GDALRasterIO( rasterBand, GF_Read, 0, 0, xSize, 1, &scanLine2[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
446 CPLFree( scanLine1 );
447 scanLine1 = scanLine2;
448 scanLine2 = scanLine3;
449 scanLine3 = (
float * ) CPLMalloc( bufferSize );
453 if ( yIndex == ySize - 1 )
455 for (
int a = 0; a < xSize + 2; ++a )
462 if ( GDALRasterIO( rasterBand, GF_Read, 0, yIndex + 1, xSize, 1, &scanLine3[1], xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
474 for (
int xIndex = 0; xIndex < xSize; ++xIndex )
478 =
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] );
481 if ( GDALRasterIO( outputRasterBand, GF_Write, 0, yIndex, xSize, 1, resultLine, xSize, 1, GDT_Float32, 0, 0 ) != CE_None )
487 CPLFree( resultLine );
488 CPLFree( scanLine1 );
489 CPLFree( scanLine2 );
490 CPLFree( scanLine3 );
498#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 13, 0 )
499 else if ( hasReportsDuringClose && feedback )
501 QgsGdalProgressAdapter progress( feedback, maxProgressDuringBlockWriting );
@ 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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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)