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 CachedTile tmp = std::move(m_aCachedTiles[i]);
175 for( int j = i; j >= 1; --j )
176 m_aCachedTiles[j] = std::move(m_aCachedTiles[j-1]);
177 m_aCachedTiles[0] = std::move(tmp);
178 if( pbSuccess )
179 *pbSuccess = true;
180 return ret;
181 }
182 }
183 if( !LoadTile(nTileX, nTileY) )
184 {
185 if( pbSuccess )
186 *pbSuccess = false;
187 return 0;
188 }
189 if( pbSuccess )
190 *pbSuccess = true;
191 return m_aCachedTiles[0].m_data[nYInTile * TILE_SIZE + nXInTile];
192 }
193
194 /************************************************************************/
195 /* Set() */
196 /************************************************************************/
197
214 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
215 inline
216 bool GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::Set(int nX, int nY, Type val)
217 {
218 const int nTileX = nX / TILE_SIZE;
219 const int nTileY = nY / TILE_SIZE;
220 const int nXInTile = nX % TILE_SIZE;
221 const int nYInTile = nY % TILE_SIZE;
222 if( m_aCachedTiles[0].m_nTileX == nTileX &&
223 m_aCachedTiles[0].m_nTileY == nTileY )
224 {
225 m_aCachedTiles[0].m_data[nYInTile * TILE_SIZE + nXInTile] = val;
226 m_aCachedTiles[0].m_bModified = true;
227 return true;
228 }
229 return SetSlowPath(nTileX, nTileY, nXInTile, nYInTile, val);
230 }
231
232 /************************************************************************/
233 /* SetSlowPath() */
234 /************************************************************************/
235
236 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
237 bool GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::SetSlowPath(
238 int nTileX, int nTileY, int nXInTile, int nYInTile, Type val)
239 {
240 for( int i = 1; i < m_nCachedTileCount; ++i )
241 {
242 auto& cachedTile = m_aCachedTiles[i];
243 if( cachedTile.m_nTileX == nTileX &&
244 cachedTile.m_nTileY == nTileY )
245 {
246 cachedTile.m_data[nYInTile * TILE_SIZE + nXInTile] = val;
247 cachedTile.m_bModified = true;
248 if( i > 0 )
249 {
250 CachedTile tmp = std::move(m_aCachedTiles[i]);
251 for( int j = i; j >= 1; --j )
252 m_aCachedTiles[j] = std::move(m_aCachedTiles[j-1]);
253 m_aCachedTiles[0] = std::move(tmp);
254 }
255 return true;
256 }
257 }
258 if( !LoadTile(nTileX, nTileY) )
259 {
260 return false;
261 }
262 m_aCachedTiles[0].m_data[nYInTile * TILE_SIZE + nXInTile] = val;
263 m_aCachedTiles[0].m_bModified = true;
264 return true;
265 }
266
267 /************************************************************************/
268 /* FlushCache() */
269 /************************************************************************/
270
275 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
276 bool GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::FlushCache()
277 {
278 bool bRet = true;
279 for( int i = 0; i < m_nCachedTileCount; ++i )
280 {
281 if( !FlushTile(i) )
282 bRet = false;
283 m_aCachedTiles[i].m_nTileX = -1;
284 m_aCachedTiles[i].m_nTileY = -1;
285 }
286 return bRet;
287 }
288
289 /************************************************************************/
290 /* ResetModifiedFlag() */
291 /************************************************************************/
292
295 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
296 void GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::ResetModifiedFlag()
297 {
298 for( int i = 0; i < m_nCachedTileCount; ++i )
299 {
300 m_aCachedTiles[i].m_bModified = false;
301 }
302 }
303
304 /************************************************************************/
305 /* GDALCachedPixelAccessorGetDataType */
306 /************************************************************************/
307
309 template<class T> struct GDALCachedPixelAccessorGetDataType {};
310
311 template<> struct GDALCachedPixelAccessorGetDataType<GByte> { static constexpr GDALDataType DataType = GDT_Byte; };
312 template<> struct GDALCachedPixelAccessorGetDataType<GUInt16> { static constexpr GDALDataType DataType = GDT_UInt16; };
313 template<> struct GDALCachedPixelAccessorGetDataType<GInt16> { static constexpr GDALDataType DataType = GDT_Int16; };
314 template<> struct GDALCachedPixelAccessorGetDataType<GUInt32> { static constexpr GDALDataType DataType = GDT_UInt32; };
315 template<> struct GDALCachedPixelAccessorGetDataType<GInt32> { static constexpr GDALDataType DataType = GDT_Int32; };
316 #if SIZEOF_UNSIGNED_LONG == 8
317 // std::uint64_t on Linux 64-bit resolves as unsigned long
318 template<> struct GDALCachedPixelAccessorGetDataType<unsigned long> { static constexpr GDALDataType DataType = GDT_UInt64; };
319 template<> struct GDALCachedPixelAccessorGetDataType<long > { static constexpr GDALDataType DataType = GDT_Int64; };
320 #endif
321 template<> struct GDALCachedPixelAccessorGetDataType<GUInt64> { static constexpr GDALDataType DataType = GDT_UInt64; };
322 template<> struct GDALCachedPixelAccessorGetDataType<GInt64> { static constexpr GDALDataType DataType = GDT_Int64; };
323 template<> struct GDALCachedPixelAccessorGetDataType<float> { static constexpr GDALDataType DataType = GDT_Float32; };
324 template<> struct GDALCachedPixelAccessorGetDataType<double> { static constexpr GDALDataType DataType = GDT_Float64; };
327 /************************************************************************/
328 /* LoadTile() */
329 /************************************************************************/
330
331 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
332 bool GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::LoadTile(int nTileX, int nTileY)
333 {
334 if( m_nCachedTileCount == CACHED_TILE_COUNT )
335 {
336 if( !FlushTile(CACHED_TILE_COUNT - 1) )
337 return false;
338 CachedTile tmp = std::move(m_aCachedTiles[CACHED_TILE_COUNT-1]);
339 for( int i = CACHED_TILE_COUNT - 1; i >= 1; --i )
340 m_aCachedTiles[i] = std::move(m_aCachedTiles[i-1]);
341 m_aCachedTiles[0] = std::move(tmp);
342 }
343 else
344 {
345 if( m_nCachedTileCount > 0 )
346 std::swap(m_aCachedTiles[0], m_aCachedTiles[m_nCachedTileCount]);
347 m_aCachedTiles[0].m_data.resize(TILE_SIZE * TILE_SIZE);
348 m_nCachedTileCount ++;
349 }
350
351 #if 0
352 CPLDebug("GDAL", "Load tile(%d, %d) of band %d of dataset %s",
353 nTileX, nTileY, m_poBand->GetBand(),
354 m_poBand->GetDataset() ? m_poBand->GetDataset()->GetDescription() : "(unknown)");
355 #endif
356 CPLAssert(!m_aCachedTiles[0].m_bModified);
357 const int nXOff = nTileX * TILE_SIZE;
358 const int nYOff = nTileY * TILE_SIZE;
359 const int nReqXSize = std::min(m_poBand->GetXSize() - nXOff, TILE_SIZE);
360 const int nReqYSize = std::min(m_poBand->GetYSize() - nYOff, TILE_SIZE);
361 if( m_poBand->RasterIO(GF_Read, nXOff, nYOff, nReqXSize, nReqYSize,
362 m_aCachedTiles[0].m_data.data(),
363 nReqXSize, nReqYSize,
364 GDALCachedPixelAccessorGetDataType<Type>::DataType,
365 sizeof(Type), TILE_SIZE * sizeof(Type),
366 nullptr) != CE_None )
367 {
368 m_aCachedTiles[0].m_nTileX = -1;
369 m_aCachedTiles[0].m_nTileY = -1;
370 return false;
371 }
372 m_aCachedTiles[0].m_nTileX = nTileX;
373 m_aCachedTiles[0].m_nTileY = nTileY;
374 return true;
375 }
376
377 /************************************************************************/
378 /* FlushTile() */
379 /************************************************************************/
380
381 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
382 bool GDALCachedPixelAccessor<Type, TILE_SIZE, CACHED_TILE_COUNT>::FlushTile(int iSlot)
383 {
384 if( !m_aCachedTiles[iSlot].m_bModified )
385 return true;
386
387 m_aCachedTiles[iSlot].m_bModified = false;
388 const int nXOff = m_aCachedTiles[iSlot].m_nTileX * TILE_SIZE;
389 const int nYOff = m_aCachedTiles[iSlot].m_nTileY * TILE_SIZE;
390 const int nReqXSize = std::min(m_poBand->GetXSize() - nXOff, TILE_SIZE);
391 const int nReqYSize = std::min(m_poBand->GetYSize() - nYOff, TILE_SIZE);
392 return m_poBand->RasterIO(GF_Write, nXOff, nYOff, nReqXSize, nReqYSize,
393 m_aCachedTiles[iSlot].m_data.data(),
394 nReqXSize, nReqYSize,
395 GDALCachedPixelAccessorGetDataType<Type>::DataType,
396 sizeof(Type), TILE_SIZE * sizeof(Type),
397 nullptr) == CE_None;
398 }
399
400 #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:296
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:1179
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
CPLDebug
void CPLDebug(const char *, const char *,...)
Display a debugging message.
Definition: cpl_error.cpp:606
GDALCachedPixelAccessor::Set
bool Set(int nX, int nY, Type val)
Set the value of a pixel.
Definition: gdalcachedpixelaccessor.h:216
GDALCachedPixelAccessor::FlushCache
bool FlushCache()
Flush content of modified tiles and drop caches.
Definition: gdalcachedpixelaccessor.h:276
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