GDAL

gdalcachedpixelaccessor.h
1 /******************************************************************************
2 *
3 * Project: GDAL
4 * Purpose: Fast access to individual pixels in a GDALRasterBand
5 * Author: Even Rouault <even dot rouault at spatialys.com>
6 *
7 ******************************************************************************
8 * Copyright (c) 2022, Planet Labs
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 ****************************************************************************/
28
29 #ifndef GDAL_CACHED_PIXEL_ACCESSOR_INCLUDED
30 #define GDAL_CACHED_PIXEL_ACCESSOR_INCLUDED
31
32 #include "gdal_priv.h"
33 #include "cpl_error.h"
34
35 #include <algorithm>
36 #include <array>
37 #include <vector>
38
39 /************************************************************************/
40 /* GDALCachedPixelAccessor */
41 /************************************************************************/
42
51 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT = 4> class GDALCachedPixelAccessor
52 {
53 GDALRasterBand* m_poBand = nullptr;
54
55 struct CachedTile
56 {
57 std::vector<Type> m_data{};
58 int m_nTileX = -1;
59 int m_nTileY = -1;
60 bool m_bModified = false;
61 };
62
63 int m_nCachedTileCount = 0;
64 std::array<CachedTile, CACHED_TILE_COUNT> m_aCachedTiles{};
65
66 bool LoadTile(int nTileX, int nTileY);
67 bool FlushTile(int iSlot);
68
69 Type GetSlowPath(int nTileX, int nTileY,
70 int nXInTile, int nYInTile,
71 bool* pbSuccess);
72 bool SetSlowPath(int nTileX, int nTileY,
73 int nXInTile, int nYInTile,
74 Type val);
75
76 GDALCachedPixelAccessor(const GDALCachedPixelAccessor&) = delete;
77 GDALCachedPixelAccessor& operator= (const GDALCachedPixelAccessor&) = delete;
78
79 public:
80 explicit GDALCachedPixelAccessor(GDALRasterBand* poBand);
81 ~GDALCachedPixelAccessor();
82
84 void SetBand(GDALRasterBand* poBand) { m_poBand = poBand; }
85
86 Type Get(int nX, int nY, bool* pbSuccess = nullptr);
87 bool Set(int nX, int nY, Type val);
88
89 bool FlushCache();
90 void ResetModifiedFlag();
91 };
92
93
94 /************************************************************************/
95 /* GDALCachedPixelAccessor() */
96 /************************************************************************/
97
109 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
110 GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::GDALCachedPixelAccessor(GDALRasterBand* poBand): m_poBand(poBand)
111 {
112 }
113
114 /************************************************************************/
115 /* ~GDALCachedPixelAccessor() */
116 /************************************************************************/
117
122 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
123 GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::~GDALCachedPixelAccessor()
124 {
125 FlushCache();
126 }
127
128 /************************************************************************/
129 /* Get() */
130 /************************************************************************/
131
141 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
142 inline
143 Type GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::Get(int nX, int nY, bool* pbSuccess)
144 {
145 const int nTileX = nX / TILE_SIZE;
146 const int nTileY = nY / TILE_SIZE;
147 const int nXInTile = nX % TILE_SIZE;
148 const int nYInTile = nY % TILE_SIZE;
149 if( m_aCachedTiles[0].m_nTileX == nTileX &&
150 m_aCachedTiles[0].m_nTileY == nTileY )
151 {
152 if( pbSuccess )
153 *pbSuccess = true;
154 return m_aCachedTiles[0].m_data[nYInTile * TILE_SIZE + nXInTile];
155 }
156 return GetSlowPath(nTileX, nTileY, nXInTile, nYInTile, pbSuccess);
157 }
158
159 /************************************************************************/
160 /* GetSlowPath() */
161 /************************************************************************/
162
163 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
164 Type GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::GetSlowPath(
165 int nTileX, int nTileY, int nXInTile, int nYInTile, bool* pbSuccess)
166 {
167 for( int i = 1; i < m_nCachedTileCount; ++i )
168 {
169 const auto& cachedTile = m_aCachedTiles[i];
170 if( cachedTile.m_nTileX == nTileX &&
171 cachedTile.m_nTileY == nTileY )
172 {
173 const auto ret = cachedTile.m_data[nYInTile * TILE_SIZE + nXInTile];
174 std::swap(m_aCachedTiles[0], m_aCachedTiles[i]);
175 if( pbSuccess )
176 *pbSuccess = true;
177 return ret;
178 }
179 }
180 if( !LoadTile(nTileX, nTileY) )
181 {
182 if( pbSuccess )
183 *pbSuccess = false;
184 return 0;
185 }
186 if( pbSuccess )
187 *pbSuccess = true;
188 return m_aCachedTiles[0].m_data[nYInTile * TILE_SIZE + nXInTile];
189 }
190
191 /************************************************************************/
192 /* Set() */
193 /************************************************************************/
194
211 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
212 inline
213 bool GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::Set(int nX, int nY, Type val)
214 {
215 const int nTileX = nX / TILE_SIZE;
216 const int nTileY = nY / TILE_SIZE;
217 const int nXInTile = nX % TILE_SIZE;
218 const int nYInTile = nY % TILE_SIZE;
219 if( m_aCachedTiles[0].m_nTileX == nTileX &&
220 m_aCachedTiles[0].m_nTileY == nTileY )
221 {
222 m_aCachedTiles[0].m_data[nYInTile * TILE_SIZE + nXInTile] = val;
223 m_aCachedTiles[0].m_bModified = true;
224 return true;
225 }
226 return SetSlowPath(nTileX, nTileY, nXInTile, nYInTile, val);
227 }
228
229 /************************************************************************/
230 /* SetSlowPath() */
231 /************************************************************************/
232
233 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
234 bool GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::SetSlowPath(
235 int nTileX, int nTileY, int nXInTile, int nYInTile, Type val)
236 {
237 for( int i = 1; i < m_nCachedTileCount; ++i )
238 {
239 auto& cachedTile = m_aCachedTiles[i];
240 if( cachedTile.m_nTileX == nTileX &&
241 cachedTile.m_nTileY == nTileY )
242 {
243 cachedTile.m_data[nYInTile * TILE_SIZE + nXInTile] = val;
244 cachedTile.m_bModified = true;
245 if( i > 0 )
246 std::swap(m_aCachedTiles[0], m_aCachedTiles[i]);
247 return true;
248 }
249 }
250 if( !LoadTile(nTileX, nTileY) )
251 {
252 return false;
253 }
254 m_aCachedTiles[0].m_data[nYInTile * TILE_SIZE + nXInTile] = val;
255 m_aCachedTiles[0].m_bModified = true;
256 return true;
257 }
258
259 /************************************************************************/
260 /* FlushCache() */
261 /************************************************************************/
262
267 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
268 bool GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::FlushCache()
269 {
270 bool bRet = true;
271 for( int i = 0; i < m_nCachedTileCount; ++i )
272 {
273 if( !FlushTile(i) )
274 bRet = false;
275 m_aCachedTiles[i].m_nTileX = -1;
276 m_aCachedTiles[i].m_nTileY = -1;
277 }
278 return bRet;
279 }
280
281 /************************************************************************/
282 /* ResetModifiedFlag() */
283 /************************************************************************/
284
287 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
288 void GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::ResetModifiedFlag()
289 {
290 for( int i = 0; i < m_nCachedTileCount; ++i )
291 {
292 m_aCachedTiles[i].m_bModified = false;
293 }
294 }
295
296 /************************************************************************/
297 /* GDALCachedPixelAccessorGetDataType */
298 /************************************************************************/
299
301 template<class T> struct GDALCachedPixelAccessorGetDataType {};
302
303 template<> struct GDALCachedPixelAccessorGetDataType<GByte> { static constexpr GDALDataType DataType = GDT_Byte; };
304 template<> struct GDALCachedPixelAccessorGetDataType<GUInt16> { static constexpr GDALDataType DataType = GDT_UInt16; };
305 template<> struct GDALCachedPixelAccessorGetDataType<GInt16> { static constexpr GDALDataType DataType = GDT_Int16; };
306 template<> struct GDALCachedPixelAccessorGetDataType<GUInt32> { static constexpr GDALDataType DataType = GDT_UInt32; };
307 template<> struct GDALCachedPixelAccessorGetDataType<GInt32> { static constexpr GDALDataType DataType = GDT_Int32; };
308 #if SIZEOF_UNSIGNED_LONG == 8
309 // std::uint64_t on Linux 64-bit resolves as unsigned long
310 template<> struct GDALCachedPixelAccessorGetDataType<unsigned long> { static constexpr GDALDataType DataType = GDT_UInt64; };
311 template<> struct GDALCachedPixelAccessorGetDataType<long > { static constexpr GDALDataType DataType = GDT_Int64; };
312 #endif
313 template<> struct GDALCachedPixelAccessorGetDataType<GUInt64> { static constexpr GDALDataType DataType = GDT_UInt64; };
314 template<> struct GDALCachedPixelAccessorGetDataType<GInt64> { static constexpr GDALDataType DataType = GDT_Int64; };
315 template<> struct GDALCachedPixelAccessorGetDataType<float> { static constexpr GDALDataType DataType = GDT_Float32; };
316 template<> struct GDALCachedPixelAccessorGetDataType<double> { static constexpr GDALDataType DataType = GDT_Float64; };
319 /************************************************************************/
320 /* LoadTile() */
321 /************************************************************************/
322
323 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
324 bool GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::LoadTile(int nTileX, int nTileY)
325 {
326 if( m_nCachedTileCount == CACHED_TILE_COUNT )
327 {
328 if( !FlushTile(CACHED_TILE_COUNT - 1) )
329 return false;
330 std::swap(m_aCachedTiles[0], m_aCachedTiles[CACHED_TILE_COUNT - 1]);
331 }
332 else
333 {
334 if( m_nCachedTileCount > 0 )
335 std::swap(m_aCachedTiles[0], m_aCachedTiles[m_nCachedTileCount]);
336 m_aCachedTiles[0].m_data.resize(TILE_SIZE * TILE_SIZE);
337 m_nCachedTileCount ++;
338 }
339
340 CPLAssert(!m_aCachedTiles[0].m_bModified);
341 const int nXOff = nTileX * TILE_SIZE;
342 const int nYOff = nTileY * TILE_SIZE;
343 const int nReqXSize = std::min(m_poBand->GetXSize() - nXOff, TILE_SIZE);
344 const int nReqYSize = std::min(m_poBand->GetYSize() - nYOff, TILE_SIZE);
345 if( m_poBand->RasterIO(GF_Read, nXOff, nYOff, nReqXSize, nReqYSize,
346 m_aCachedTiles[0].m_data.data(),
347 nReqXSize, nReqYSize,
348 GDALCachedPixelAccessorGetDataType<Type>::DataType,
349 sizeof(Type), TILE_SIZE * sizeof(Type),
350 nullptr) != CE_None )
351 {
352 m_aCachedTiles[0].m_nTileX = -1;
353 m_aCachedTiles[0].m_nTileY = -1;
354 return false;
355 }
356 m_aCachedTiles[0].m_nTileX = nTileX;
357 m_aCachedTiles[0].m_nTileY = nTileY;
358 return true;
359 }
360
361 /************************************************************************/
362 /* FlushTile() */
363 /************************************************************************/
364
365 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
366 bool GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::FlushTile(int iSlot)
367 {
368 if( !m_aCachedTiles[iSlot].m_bModified )
369 return true;
370
371 m_aCachedTiles[iSlot].m_bModified = false;
372 const int nXOff = m_aCachedTiles[iSlot].m_nTileX * TILE_SIZE;
373 const int nYOff = m_aCachedTiles[iSlot].m_nTileY * TILE_SIZE;
374 const int nReqXSize = std::min(m_poBand->GetXSize() - nXOff, TILE_SIZE);
375 const int nReqYSize = std::min(m_poBand->GetYSize() - nYOff, TILE_SIZE);
376 return m_poBand->RasterIO(GF_Write, nXOff, nYOff, nReqXSize, nReqYSize,
377 m_aCachedTiles[iSlot].m_data.data(),
378 nReqXSize, nReqYSize,
379 GDALCachedPixelAccessorGetDataType<Type>::DataType,
380 sizeof(Type), TILE_SIZE * sizeof(Type),
381 nullptr) == CE_None;
382 }
383
384 #endif // GDAL_PIXEL_ACCESSOR_INCLUDED
GDT_Int32
@ GDT_Int32
Definition: gdal.h:69
GByte
unsigned char GByte
Unsigned byte type.
Definition: cpl_port.h:203
GUInt64
GUIntBig GUInt64
Unsigned 64 bit integer type.
Definition: cpl_port.h:251
GDT_UInt64
@ GDT_UInt64
Definition: gdal.h:70
GDALCachedPixelAccessor
Class to have reasonably fast random pixel access to a raster band, when accessing multiple pixels th...
Definition: gdalcachedpixelaccessor.h:51
GInt16
short GInt16
Int16 type.
Definition: cpl_port.h:199
GDT_Float32
@ GDT_Float32
Definition: gdal.h:72
cpl_error.h
GDALCachedPixelAccessor::ResetModifiedFlag
void ResetModifiedFlag()
Reset the modified flag for cached tiles.
Definition: gdalcachedpixelaccessor.h:288
GDT_UInt32
@ GDT_UInt32
Definition: gdal.h:68
GF_Read
@ GF_Read
Definition: gdal.h:123
GDALRasterBand
A single raster band (or channel).
Definition: gdal_priv.h:1150
GInt64
GIntBig GInt64
Signed 64 bit integer type.
Definition: cpl_port.h:249
GDALDataType
GDALDataType
Definition: gdal.h:63
GDALCachedPixelAccessor::~GDALCachedPixelAccessor
~GDALCachedPixelAccessor()
Destructor.
Definition: gdalcachedpixelaccessor.h:123
GDALCachedPixelAccessor::Get
Type Get(int nX, int nY, bool *pbSuccess=nullptr)
Get the value of a pixel.
Definition: gdalcachedpixelaccessor.h:143
GDT_UInt16
@ GDT_UInt16
Definition: gdal.h:66
CPLAssert
#define CPLAssert(expr)
Assert on an expression.
Definition: cpl_error.h:198
GF_Write
@ GF_Write
Definition: gdal.h:124
GDT_Float64
@ GDT_Float64
Definition: gdal.h:73
GDALCachedPixelAccessor::Set
bool Set(int nX, int nY, Type val)
Set the value of a pixel.
Definition: gdalcachedpixelaccessor.h:213
GDALCachedPixelAccessor::FlushCache
bool FlushCache()
Flush content of modified tiles and drop caches.
Definition: gdalcachedpixelaccessor.h:268
gdal_priv.h
GDT_Int64
@ GDT_Int64
Definition: gdal.h:71
GDT_Int16
@ GDT_Int16
Definition: gdal.h:67
GDT_Byte
@ GDT_Byte
Definition: gdal.h:65
GDALCachedPixelAccessor::SetBand
void SetBand(GDALRasterBand *poBand)
Assign the raster band if not known at construction time.
Definition: gdalcachedpixelaccessor.h:110
GUInt16
unsigned short GUInt16
Unsigned int16 type.
Definition: cpl_port.h:201
GInt32
int GInt32
Int32 type.
Definition: cpl_port.h:193
GUInt32
unsigned int GUInt32
Unsigned int32 type.
Definition: cpl_port.h:195