Skip to content

Commit 109fcc0

Browse files
authored
Merge pull request #9070 from elpaso/bugfix-21121-opencl-16bit-raster
Fix hillshade renderer with data type != Float32 [opencl]
2 parents 3c9b6e5 + 1923967 commit 109fcc0

File tree

2 files changed

+44
-11
lines changed

2 files changed

+44
-11
lines changed

resources/opencl_programs/hillshade_renderer.cl

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Note: "float *scanLine" may be replaced by code with actual input data type
12
__kernel void processNineCellWindow( __global float *scanLine1,
23
__global float *scanLine2,
34
__global float *scanLine3,
@@ -39,8 +40,8 @@ __kernel void processNineCellWindow( __global float *scanLine1,
3940
if ( x32 == rasterParams[0] ) x32 = x22;
4041
if ( x33 == rasterParams[0] ) x33 = x22;
4142

42-
float derX = ( ( x13 + x23 + x23 + x33 ) - ( x11 + x21 + x21 + x31 ) ) / ( 8 * rasterParams[3] );
43-
float derY = ( ( x31 + x32 + x32 + x33 ) - ( x11 + x12 + x12 + x13 ) ) / ( 8 * -rasterParams[4]);
43+
float derX = ( ( x13 + x23 + x23 + x33 ) - ( x11 + x21 + x21 + x31 ) ) / ( 8.0f * rasterParams[3] );
44+
float derY = ( ( x31 + x32 + x32 + x33 ) - ( x11 + x12 + x12 + x13 ) ) / ( 8.0f * -rasterParams[4]);
4445

4546
if ( derX == rasterParams[0] ||
4647
derX == rasterParams[0] )
@@ -90,7 +91,7 @@ __kernel void processNineCellWindow( __global float *scanLine1,
9091
weight_270 * val270_mul_127 +
9192
weight_315 * val315_mul_127 +
9293
weight_360 * val360_mul_127 ) / xx_plus_yy ) /
93-
( 1 + rasterParams[8] * xx_plus_yy );
94+
( 1.0f + rasterParams[8] * xx_plus_yy );
9495
res = clamp( 1.0f + cang_mul_127, 0.0f, 255.0f );
9596
}
9697
}
@@ -99,7 +100,7 @@ __kernel void processNineCellWindow( __global float *scanLine1,
99100
res = ( rasterParams[9] -
100101
( derY * rasterParams[6] -
101102
derX * rasterParams[7] )) /
102-
sqrt( 1 + rasterParams[8] *
103+
sqrt( 1.0f + rasterParams[8] *
103104
( derX * derX + derY * derY ) );
104105
res = res <= 0.0f ? 1.0f : 1.0f + res;
105106
}

src/core/raster/qgshillshaderenderer.cpp

+39-7
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <chrono>
3131
#include "qgssettings.h"
3232
#endif
33+
#include "qgsexception.h"
3334
#include "qgsopenclutils.h"
3435
#endif
3536

@@ -165,7 +166,8 @@ QgsRasterBlock *QgsHillshadeRenderer::block( int bandNo, const QgsRectangle &ext
165166
bool useOpenCL( QgsOpenClUtils::enabled()
166167
&& QgsOpenClUtils::available()
167168
&& ( ! mRasterTransparency || mRasterTransparency->isEmpty() )
168-
&& mAlphaBand <= 0 );
169+
&& mAlphaBand <= 0
170+
&& inputBlock->dataTypeSize() <= 4 );
169171
// Check for sources
170172
QString source;
171173
if ( useOpenCL )
@@ -190,6 +192,36 @@ QgsRasterBlock *QgsHillshadeRenderer::block( int bandNo, const QgsRectangle &ext
190192
std::size_t inputDataTypeSize = inputBlock->dataTypeSize();
191193
std::size_t outputDataTypeSize = outputBlock->dataTypeSize();
192194
// Buffer scanline, 1px height, 2px wider
195+
QString typeName;
196+
switch ( inputBlock->dataType() )
197+
{
198+
case Qgis::DataType::Byte:
199+
typeName = QStringLiteral( "unsigned char" );
200+
break;
201+
case Qgis::DataType::UInt16:
202+
typeName = QStringLiteral( "unsigned int" );
203+
break;
204+
case Qgis::DataType::Int16:
205+
typeName = QStringLiteral( "short" );
206+
break;
207+
case Qgis::DataType::UInt32:
208+
typeName = QStringLiteral( "unsigned int" );
209+
break;
210+
case Qgis::DataType::Int32:
211+
typeName = QStringLiteral( "int" );
212+
break;
213+
case Qgis::DataType::Float32:
214+
typeName = QStringLiteral( "float" );
215+
break;
216+
default:
217+
throw QgsException( QStringLiteral( "Unsupported data type for OpenCL processing." ) );
218+
}
219+
220+
if ( inputBlock->dataType() != Qgis::DataType::Float32 )
221+
{
222+
source.replace( QStringLiteral( "__global float *scanLine" ), QStringLiteral( "__global %1 *scanLine" ).arg( typeName ) );
223+
}
224+
193225
// Data type for input is Float32 (4 bytes)
194226
std::size_t scanLineWidth( inputBlock->width() + 2 );
195227
std::size_t inputSize( inputDataTypeSize * inputBlock->width() );
@@ -236,7 +268,6 @@ QgsRasterBlock *QgsHillshadeRenderer::block( int bandNo, const QgsRectangle &ext
236268
// Whether use multidirectional
237269
rasterParams.push_back( static_cast<float>( mMultiDirectional ) ); // 17
238270

239-
240271
cl::Buffer rasterParamsBuffer( queue, rasterParams.begin(), rasterParams.end(), true, false, nullptr );
241272
cl::Buffer scanLine1Buffer( ctx, CL_MEM_READ_ONLY, bufferSize, nullptr, nullptr );
242273
cl::Buffer scanLine2Buffer( ctx, CL_MEM_READ_ONLY, bufferSize, nullptr, nullptr );
@@ -245,13 +276,14 @@ QgsRasterBlock *QgsHillshadeRenderer::block( int bandNo, const QgsRectangle &ext
245276
// Note that result buffer is an image
246277
cl::Buffer resultLineBuffer( ctx, CL_MEM_WRITE_ONLY, outputDataTypeSize * width, nullptr, nullptr );
247278

248-
static cl::Program program;
249-
static std::once_flag programBuilt;
250-
std::call_once( programBuilt, [ = ]()
279+
static std::map<Qgis::DataType, cl::Program> programCache;
280+
cl::Program program = programCache[inputBlock->dataType()];
281+
if ( ! program.get() )
251282
{
252283
// Create a program from the kernel source
253-
program = QgsOpenClUtils::buildProgram( source, QgsOpenClUtils::ExceptionBehavior::Throw );
254-
} );
284+
programCache[inputBlock->dataType()] = QgsOpenClUtils::buildProgram( source, QgsOpenClUtils::ExceptionBehavior::Throw );
285+
program = programCache[inputBlock->dataType()];
286+
}
255287

256288
// Disable program cache when developing and testing cl program
257289
// program = QgsOpenClUtils::buildProgram( ctx, source, QgsOpenClUtils::ExceptionBehavior::Throw );

0 commit comments

Comments
 (0)