Skip to content

Commit 3054da0

Browse files
committed
Use OpenCL command queue
1 parent 215bfd4 commit 3054da0

File tree

11 files changed

+272
-255
lines changed

11 files changed

+272
-255
lines changed

resources/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ INSTALL(DIRECTORY themes DESTINATION ${QGIS_DATA_DIR}/resources)
1111
INSTALL(DIRECTORY data DESTINATION ${QGIS_DATA_DIR}/resources)
1212
INSTALL(DIRECTORY metadata-ISO DESTINATION ${QGIS_DATA_DIR}/resources)
1313
INSTALL(DIRECTORY palettes DESTINATION ${QGIS_DATA_DIR}/resources)
14+
IF (HAVE_OPENCL)
15+
INSTALL(DIRECTORY opencl_programs DESTINATION ${QGIS_DATA_DIR}/resources)
16+
ENDIF (HAVE_OPENCL)
1417

1518
IF (WITH_SERVER)
1619
INSTALL(DIRECTORY server DESTINATION ${QGIS_DATA_DIR}/resources)

resources/opencl_programs/aspect.cl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#include "calcfirstder.cl"
2+
3+
__kernel void processNineCellWindow( __global float *scanLine1,
4+
__global float *scanLine2,
5+
__global float *scanLine3,
6+
__global float *resultLine,
7+
__global float *rasterParams
8+
) {
9+
10+
// Get the index of the current element
11+
const int i = get_global_id(0);
12+
13+
// Do the operation
14+
//return (( (x31 - x11) + 2 * (x32 - x12) + (x33 - x13) ) / (8 * mCellSizeX))
15+
float derX = calcFirstDer( scanLine1[i], scanLine2[i], scanLine3[i],
16+
scanLine1[i+1], scanLine2[i+1], scanLine3[i+1],
17+
scanLine1[i+2], scanLine2[i+2], scanLine3[i+2],
18+
rasterParams[0], rasterParams[1], rasterParams[2], rasterParams[3]
19+
);
20+
//return (((x11 - x13) + 2 * (x21 - x23) + (x31 - x33)) / ( 8 * mCellSizeY));
21+
float derY = calcFirstDer( scanLine1[i+2], scanLine1[i+1], scanLine1[i],
22+
scanLine2[i+2], scanLine2[i+1], scanLine2[i],
23+
scanLine3[i+2], scanLine3[i+1], scanLine3[i],
24+
rasterParams[0], rasterParams[1], rasterParams[2], rasterParams[4]
25+
);
26+
27+
28+
if ( derX == rasterParams[1] || derY == rasterParams[1] ||
29+
( derX == 0.0f && derY == 0.0f) )
30+
{
31+
resultLine[i] = rasterParams[1];
32+
}
33+
else
34+
{
35+
// 180.0 / M_PI = 57.29577951308232
36+
float aspect = atan2( derX, derY ) * 57.29577951308232;
37+
if ( aspect < 0 )
38+
resultLine[i] = 90.0f - aspect;
39+
else if (aspect > 90.0f)
40+
// 360 + 90 = 450
41+
resultLine[i] = 450.0f - aspect;
42+
else
43+
resultLine[i] = 90.0 - aspect;
44+
}
45+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Calculate the first derivative from a 3x3 cell matrix
2+
float calcFirstDer( float x11, float x21, float x31, float x12, float x22, float x32, float x13, float x23, float x33,
3+
float inputNodataValue, float outputNodataValue, float zFactor, float mCellSize )
4+
{
5+
//the basic formula would be simple, but we need to test for nodata values...
6+
//X: return (( (x31 - x11) + 2 * (x32 - x12) + (x33 - x13) ) / (8 * cellSizeX));
7+
//Y: return (((x11 - x13) + 2 * (x21 - x23) + (x31 - x33)) / ( 8 * cellSizeY));
8+
9+
int weight = 0;
10+
float sum = 0;
11+
12+
13+
//first row
14+
if ( x31 != inputNodataValue && x11 != inputNodataValue ) //the normal case
15+
{
16+
sum += ( x31 - x11 );
17+
weight += 2;
18+
}
19+
else if ( x31 == inputNodataValue && x11 != inputNodataValue && x21 != inputNodataValue ) //probably 3x3 window is at the border
20+
{
21+
sum += ( x21 - x11 );
22+
weight += 1;
23+
}
24+
else if ( x11 == inputNodataValue && x31 != inputNodataValue && x21 != inputNodataValue ) //probably 3x3 window is at the border
25+
{
26+
sum += ( x31 - x21 );
27+
weight += 1;
28+
}
29+
30+
//second row
31+
if ( x32 != inputNodataValue && x12 != inputNodataValue ) //the normal case
32+
{
33+
sum += 2.0f * ( x32 - x12 );
34+
weight += 4;
35+
}
36+
else if ( x32 == inputNodataValue && x12 != inputNodataValue && x22 != inputNodataValue )
37+
{
38+
sum += 2.0f * ( x22 - x12 );
39+
weight += 2;
40+
}
41+
else if ( x12 == inputNodataValue && x32 != inputNodataValue && x22 != inputNodataValue )
42+
{
43+
sum += 2.0f * ( x32 - x22 );
44+
weight += 2;
45+
}
46+
47+
//third row
48+
if ( x33 != inputNodataValue && x13 != inputNodataValue ) //the normal case
49+
{
50+
sum += ( x33 - x13 );
51+
weight += 2;
52+
}
53+
else if ( x33 == inputNodataValue && x13 != inputNodataValue && x23 != inputNodataValue )
54+
{
55+
sum += ( x23 - x13 );
56+
weight += 1;
57+
}
58+
else if ( x13 == inputNodataValue && x33 != inputNodataValue && x23 != inputNodataValue )
59+
{
60+
sum += ( x33 - x23 );
61+
weight += 1;
62+
}
63+
64+
if ( weight == 0 )
65+
{
66+
return outputNodataValue;
67+
}
68+
69+
return sum / ( weight * mCellSize ) * zFactor;
70+
}
71+

resources/opencl_programs/slope.cl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include "calcfirstder.cl"
2+
3+
__kernel void processNineCellWindow( __global float *scanLine1,
4+
__global float *scanLine2,
5+
__global float *scanLine3,
6+
__global float *resultLine,
7+
__global float *rasterParams
8+
) {
9+
10+
// Get the index of the current element
11+
const int i = get_global_id(0);
12+
13+
// Do the operation
14+
//return (( (x31 - x11) + 2 * (x32 - x12) + (x33 - x13) ) / (8 * mCellSizeX))
15+
float derX = calcFirstDer( scanLine1[i], scanLine2[i], scanLine3[i],
16+
scanLine1[i+1], scanLine2[i+1], scanLine3[i+1],
17+
scanLine1[i+2], scanLine2[i+2], scanLine3[i+2],
18+
rasterParams[0], rasterParams[1], rasterParams[2], rasterParams[3]
19+
);
20+
//return (((x11 - x13) + 2 * (x21 - x23) + (x31 - x33)) / ( 8 * mCellSizeY));
21+
float derY = calcFirstDer( scanLine1[i+2], scanLine1[i+1], scanLine1[i],
22+
scanLine2[i+2], scanLine2[i+1], scanLine2[i],
23+
scanLine3[i+2], scanLine3[i+1], scanLine3[i],
24+
rasterParams[0], rasterParams[1], rasterParams[2], rasterParams[4]
25+
);
26+
27+
28+
if ( derX == rasterParams[1] || derY == rasterParams[1] )
29+
{
30+
resultLine[i] = rasterParams[1];
31+
}
32+
else
33+
{
34+
float res = sqrt( derX * derX + derY * derY );
35+
res = atanpi( res );
36+
resultLine[i] = res * 180.0;
37+
}
38+
}

src/analysis/raster/aspect.cl

Lines changed: 0 additions & 114 deletions
This file was deleted.

src/analysis/raster/qgsninecellfilter.cpp

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ int QgsNineCellFilter::processRaster( QgsFeedback *feedback )
4141
if ( QgsOpenClUtils::enabled() && QgsOpenClUtils::available() && ! openClProgramBaseName( ).isEmpty() )
4242
{
4343
// Load the program sources
44-
QString source( QgsOpenClUtils::sourceFromPath( QStringLiteral( "/home/ale/dev/QGIS/src/analysis/raster/%1.cl" ).arg( openClProgramBaseName( ) ) ) );
44+
QString source( QgsOpenClUtils::sourceFromBaseName( openClProgramBaseName( ) ) );
4545
if ( ! source.isEmpty() )
4646
{
4747
try
@@ -50,19 +50,6 @@ int QgsNineCellFilter::processRaster( QgsFeedback *feedback )
5050
.arg( openClProgramBaseName( ) ), QgsOpenClUtils::LOGMESSAGE_TAG, Qgis::Info );
5151
return processRasterGPU( source, feedback );
5252
}
53-
catch ( cl::BuildError &e )
54-
{
55-
cl::BuildLogType build_logs = e.getBuildLog();
56-
QString build_log;
57-
if ( build_logs.size() > 0 )
58-
build_log = QString::fromStdString( build_logs[0].second );
59-
else
60-
build_log = QObject::tr( "Build logs not available!" );
61-
QString err = QObject::tr( "Error building OpenCL program: %1" )
62-
.arg( build_log );
63-
QgsMessageLog::logMessage( err, QgsOpenClUtils::LOGMESSAGE_TAG, Qgis::Critical );
64-
throw QgsProcessingException( err );
65-
}
6653
catch ( cl::Error &e )
6754
{
6855
QString err = QObject::tr( "Error %1 running OpenCL program in %2" )
@@ -220,18 +207,15 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee
220207
return 6;
221208
}
222209

223-
// Prepare context
210+
// Prepare context and queue
224211
cl::Context ctx = QgsOpenClUtils::context();
225212
cl::Context::setDefault( ctx );
213+
cl::CommandQueue queue( ctx );
226214

227215
//keep only three scanlines in memory at a time, make room for initial and final nodata
228216
QgsOpenClUtils::CPLAllocator<float> scanLine1( xSize + 2 );
229217
QgsOpenClUtils::CPLAllocator<float> scanLine2( xSize + 2 );
230218
QgsOpenClUtils::CPLAllocator<float> scanLine3( xSize + 2 );
231-
//float *scanLine2 = ( float * ) CPLMalloc( sizeof( float ) * ( xSize + 2 ) );
232-
//float *scanLine3 = ( float * ) CPLMalloc( sizeof( float ) * ( xSize + 2 ) );
233-
234-
//float *resultLine = ( float * ) CPLMalloc( sizeof( float ) * xSize );
235219
QgsOpenClUtils::CPLAllocator<float> resultLine( xSize );
236220

237221
cl_int errorCode = 0;
@@ -255,9 +239,7 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee
255239
cl::Buffer resultLineBuffer( CL_MEM_WRITE_ONLY, sizeof( float ) * xSize, nullptr, &errorCode );
256240

257241
// Create a program from the kernel source
258-
cl::Program program( source.toStdString() );
259-
// Use CL 1.1 for compatibility with older libs
260-
program.build( "-cl-std=CL1.1" );
242+
cl::Program program( QgsOpenClUtils::buildProgram( ctx, source, QgsOpenClUtils::ExceptionBehavior::Throw ) );
261243

262244
// Create the OpenCL kernel
263245
auto kernel = cl::KernelFunctor <
@@ -297,9 +279,6 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee
297279
else
298280
{
299281
//normally fetch only scanLine3 and release scanline 1 if we move forward one row
300-
//scanLine1 = scanLine2;
301-
//scanLine2 = scanLine3;
302-
//scanLine3 = ( float * ) CPLMalloc( sizeof( float ) * ( xSize + 2 ) );
303282
scanLine1.reset( scanLine2.release() );
304283
scanLine2.reset( scanLine3.release() );
305284
scanLine3.reset( xSize + 2 );
@@ -325,6 +304,9 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee
325304
scanLine2[0] = scanLine2[xSize + 1] = mInputNodataValue;
326305
scanLine3[0] = scanLine3[xSize + 1] = mInputNodataValue;
327306

307+
// TODO: There is room for further optimization here: instead of replacing the buffers
308+
// we could just replace just hthe new one (the top row) and switch the order
309+
// of buffer arguments in the kernell call.
328310
errorCode = cl::enqueueWriteBuffer( scanLine1Buffer, CL_TRUE, 0,
329311
sizeof( float ) * ( xSize + 2 ), scanLine1.get() );
330312
errorCode = cl::enqueueWriteBuffer( scanLine2Buffer, CL_TRUE, 0,
@@ -333,6 +315,7 @@ int QgsNineCellFilter::processRasterGPU( const QString &source, QgsFeedback *fee
333315
sizeof( float ) * ( xSize + 2 ), scanLine3.get() );
334316

335317
kernel( cl::EnqueueArgs(
318+
queue,
336319
cl::NDRange( xSize )
337320
),
338321
scanLine1Buffer,

0 commit comments

Comments
 (0)