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>
53 {
54  GDALRasterBand *m_poBand = nullptr;
55 
56  struct CachedTile
57  {
58  std::vector<Type> m_data{};
59  int m_nTileX = -1;
60  int m_nTileY = -1;
61  bool m_bModified = false;
62  };
63 
64  int m_nCachedTileCount = 0;
65  std::array<CachedTile, CACHED_TILE_COUNT> m_aCachedTiles{};
66 
67  bool LoadTile(int nTileX, int nTileY);
68  bool FlushTile(int iSlot);
69 
70  Type GetSlowPath(int nTileX, int nTileY, int nXInTile, int nYInTile,
71  bool *pbSuccess);
72  bool SetSlowPath(int nTileX, int nTileY, int nXInTile, int nYInTile,
73  Type val);
74 
77  operator=(const GDALCachedPixelAccessor &) = delete;
78 
79  public:
80  explicit GDALCachedPixelAccessor(GDALRasterBand *poBand);
82 
84  void SetBand(GDALRasterBand *poBand)
85  {
86  m_poBand = poBand;
87  }
88 
89  Type Get(int nX, int nY, bool *pbSuccess = nullptr);
90  bool Set(int nX, int nY, Type val);
91 
92  bool FlushCache();
93  void ResetModifiedFlag();
94 };
95 
96 /************************************************************************/
97 /* GDALCachedPixelAccessor() */
98 /************************************************************************/
99 
112 template <class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
115  : m_poBand(poBand)
116 {
117 }
118 
119 /************************************************************************/
120 /* ~GDALCachedPixelAccessor() */
121 /************************************************************************/
122 
127 template <class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
128 GDALCachedPixelAccessor<Type, TILE_SIZE,
129  CACHED_TILE_COUNT>::~GDALCachedPixelAccessor()
130 {
131  FlushCache();
132 }
133 
134 /************************************************************************/
135 /* Get() */
136 /************************************************************************/
137 
147 template <class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
149  int nX, int nY, bool *pbSuccess)
150 {
151  const int nTileX = nX / TILE_SIZE;
152  const int nTileY = nY / TILE_SIZE;
153  const int nXInTile = nX % TILE_SIZE;
154  const int nYInTile = nY % TILE_SIZE;
155  if (m_aCachedTiles[0].m_nTileX == nTileX &&
156  m_aCachedTiles[0].m_nTileY == nTileY)
157  {
158  if (pbSuccess)
159  *pbSuccess = true;
160  return m_aCachedTiles[0].m_data[nYInTile * TILE_SIZE + nXInTile];
161  }
162  return GetSlowPath(nTileX, nTileY, nXInTile, nYInTile, pbSuccess);
163 }
164 
165 /************************************************************************/
166 /* GetSlowPath() */
167 /************************************************************************/
168 
169 template <class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
171  int nTileX, int nTileY, int nXInTile, int nYInTile, bool *pbSuccess)
172 {
173  for (int i = 1; i < m_nCachedTileCount; ++i)
174  {
175  const auto &cachedTile = m_aCachedTiles[i];
176  if (cachedTile.m_nTileX == nTileX && cachedTile.m_nTileY == nTileY)
177  {
178  const auto ret = cachedTile.m_data[nYInTile * TILE_SIZE + nXInTile];
179  CachedTile tmp = std::move(m_aCachedTiles[i]);
180  for (int j = i; j >= 1; --j)
181  m_aCachedTiles[j] = std::move(m_aCachedTiles[j - 1]);
182  m_aCachedTiles[0] = std::move(tmp);
183  if (pbSuccess)
184  *pbSuccess = true;
185  return ret;
186  }
187  }
188  if (!LoadTile(nTileX, nTileY))
189  {
190  if (pbSuccess)
191  *pbSuccess = false;
192  return 0;
193  }
194  if (pbSuccess)
195  *pbSuccess = true;
196  return m_aCachedTiles[0].m_data[nYInTile * TILE_SIZE + nXInTile];
197 }
198 
199 /************************************************************************/
200 /* Set() */
201 /************************************************************************/
202 
219 template <class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
220 inline bool
222  Type val)
223 {
224  const int nTileX = nX / TILE_SIZE;
225  const int nTileY = nY / TILE_SIZE;
226  const int nXInTile = nX % TILE_SIZE;
227  const int nYInTile = nY % TILE_SIZE;
228  if (m_aCachedTiles[0].m_nTileX == nTileX &&
229  m_aCachedTiles[0].m_nTileY == nTileY)
230  {
231  m_aCachedTiles[0].m_data[nYInTile * TILE_SIZE + nXInTile] = val;
232  m_aCachedTiles[0].m_bModified = true;
233  return true;
234  }
235  return SetSlowPath(nTileX, nTileY, nXInTile, nYInTile, val);
236 }
237 
238 /************************************************************************/
239 /* SetSlowPath() */
240 /************************************************************************/
241 
242 template <class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
244  int nTileX, int nTileY, int nXInTile, int nYInTile, Type val)
245 {
246  for (int i = 1; i < m_nCachedTileCount; ++i)
247  {
248  auto &cachedTile = m_aCachedTiles[i];
249  if (cachedTile.m_nTileX == nTileX && cachedTile.m_nTileY == nTileY)
250  {
251  cachedTile.m_data[nYInTile * TILE_SIZE + nXInTile] = val;
252  cachedTile.m_bModified = true;
253  if (i > 0)
254  {
255  CachedTile tmp = std::move(m_aCachedTiles[i]);
256  for (int j = i; j >= 1; --j)
257  m_aCachedTiles[j] = std::move(m_aCachedTiles[j - 1]);
258  m_aCachedTiles[0] = std::move(tmp);
259  }
260  return true;
261  }
262  }
263  if (!LoadTile(nTileX, nTileY))
264  {
265  return false;
266  }
267  m_aCachedTiles[0].m_data[nYInTile * TILE_SIZE + nXInTile] = val;
268  m_aCachedTiles[0].m_bModified = true;
269  return true;
270 }
271 
272 /************************************************************************/
273 /* FlushCache() */
274 /************************************************************************/
275 
280 template <class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
282 {
283  bool bRet = true;
284  for (int i = 0; i < m_nCachedTileCount; ++i)
285  {
286  if (!FlushTile(i))
287  bRet = false;
288  m_aCachedTiles[i].m_nTileX = -1;
289  m_aCachedTiles[i].m_nTileY = -1;
290  }
291  return bRet;
292 }
293 
294 /************************************************************************/
295 /* ResetModifiedFlag() */
296 /************************************************************************/
297 
300 template <class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
301 void GDALCachedPixelAccessor<Type, TILE_SIZE,
302  CACHED_TILE_COUNT>::ResetModifiedFlag()
303 {
304  for (int i = 0; i < m_nCachedTileCount; ++i)
305  {
306  m_aCachedTiles[i].m_bModified = false;
307  }
308 }
309 
310 /************************************************************************/
311 /* GDALCachedPixelAccessorGetDataType */
312 /************************************************************************/
313 
315 template <class T> struct GDALCachedPixelAccessorGetDataType
316 {
317 };
318 
319 template <> struct GDALCachedPixelAccessorGetDataType<GByte>
320 {
321  static constexpr GDALDataType DataType = GDT_Byte;
322 };
323 
324 template <> struct GDALCachedPixelAccessorGetDataType<GInt8>
325 {
326  static constexpr GDALDataType DataType = GDT_Int8;
327 };
328 
329 template <> struct GDALCachedPixelAccessorGetDataType<GUInt16>
330 {
331  static constexpr GDALDataType DataType = GDT_UInt16;
332 };
333 
334 template <> struct GDALCachedPixelAccessorGetDataType<GInt16>
335 {
336  static constexpr GDALDataType DataType = GDT_Int16;
337 };
338 
339 template <> struct GDALCachedPixelAccessorGetDataType<GUInt32>
340 {
341  static constexpr GDALDataType DataType = GDT_UInt32;
342 };
343 
344 template <> struct GDALCachedPixelAccessorGetDataType<GInt32>
345 {
346  static constexpr GDALDataType DataType = GDT_Int32;
347 };
348 #if SIZEOF_UNSIGNED_LONG == 8
349 // std::uint64_t on Linux 64-bit resolves as unsigned long
350 template <> struct GDALCachedPixelAccessorGetDataType<unsigned long>
351 {
352  static constexpr GDALDataType DataType = GDT_UInt64;
353 };
354 
355 template <> struct GDALCachedPixelAccessorGetDataType<long>
356 {
357  static constexpr GDALDataType DataType = GDT_Int64;
358 };
359 #endif
360 template <> struct GDALCachedPixelAccessorGetDataType<GUInt64>
361 {
362  static constexpr GDALDataType DataType = GDT_UInt64;
363 };
364 
365 template <> struct GDALCachedPixelAccessorGetDataType<GInt64>
366 {
367  static constexpr GDALDataType DataType = GDT_Int64;
368 };
369 
370 template <> struct GDALCachedPixelAccessorGetDataType<float>
371 {
372  static constexpr GDALDataType DataType = GDT_Float32;
373 };
374 
375 template <> struct GDALCachedPixelAccessorGetDataType<double>
376 {
377  static constexpr GDALDataType DataType = GDT_Float64;
378 };
379 
382 /************************************************************************/
383 /* LoadTile() */
384 /************************************************************************/
385 
386 template <class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
388  int nTileX, int nTileY)
389 {
390  if (m_nCachedTileCount == CACHED_TILE_COUNT)
391  {
392  if (!FlushTile(CACHED_TILE_COUNT - 1))
393  return false;
394  CachedTile tmp = std::move(m_aCachedTiles[CACHED_TILE_COUNT - 1]);
395  for (int i = CACHED_TILE_COUNT - 1; i >= 1; --i)
396  m_aCachedTiles[i] = std::move(m_aCachedTiles[i - 1]);
397  m_aCachedTiles[0] = std::move(tmp);
398  }
399  else
400  {
401  if (m_nCachedTileCount > 0)
402  std::swap(m_aCachedTiles[0], m_aCachedTiles[m_nCachedTileCount]);
403  m_aCachedTiles[0].m_data.resize(TILE_SIZE * TILE_SIZE);
404  m_nCachedTileCount++;
405  }
406 
407 #if 0
408  CPLDebug("GDAL", "Load tile(%d, %d) of band %d of dataset %s",
409  nTileX, nTileY, m_poBand->GetBand(),
410  m_poBand->GetDataset() ? m_poBand->GetDataset()->GetDescription() : "(unknown)");
411 #endif
412  CPLAssert(!m_aCachedTiles[0].m_bModified);
413  const int nXOff = nTileX * TILE_SIZE;
414  const int nYOff = nTileY * TILE_SIZE;
415  const int nReqXSize = std::min(m_poBand->GetXSize() - nXOff, TILE_SIZE);
416  const int nReqYSize = std::min(m_poBand->GetYSize() - nYOff, TILE_SIZE);
417  if (m_poBand->RasterIO(
418  GF_Read, nXOff, nYOff, nReqXSize, nReqYSize,
419  m_aCachedTiles[0].m_data.data(), nReqXSize, nReqYSize,
420  GDALCachedPixelAccessorGetDataType<Type>::DataType, sizeof(Type),
421  TILE_SIZE * sizeof(Type), nullptr) != CE_None)
422  {
423  m_aCachedTiles[0].m_nTileX = -1;
424  m_aCachedTiles[0].m_nTileY = -1;
425  return false;
426  }
427  m_aCachedTiles[0].m_nTileX = nTileX;
428  m_aCachedTiles[0].m_nTileY = nTileY;
429  return true;
430 }
431 
432 /************************************************************************/
433 /* FlushTile() */
434 /************************************************************************/
435 
436 template <class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
438  int iSlot)
439 {
440  if (!m_aCachedTiles[iSlot].m_bModified)
441  return true;
442 
443  m_aCachedTiles[iSlot].m_bModified = false;
444  const int nXOff = m_aCachedTiles[iSlot].m_nTileX * TILE_SIZE;
445  const int nYOff = m_aCachedTiles[iSlot].m_nTileY * TILE_SIZE;
446  const int nReqXSize = std::min(m_poBand->GetXSize() - nXOff, TILE_SIZE);
447  const int nReqYSize = std::min(m_poBand->GetYSize() - nYOff, TILE_SIZE);
448  return m_poBand->RasterIO(
449  GF_Write, nXOff, nYOff, nReqXSize, nReqYSize,
450  m_aCachedTiles[iSlot].m_data.data(), nReqXSize, nReqYSize,
451  GDALCachedPixelAccessorGetDataType<Type>::DataType, sizeof(Type),
452  TILE_SIZE * sizeof(Type), nullptr) == CE_None;
453 }
454 
455 #endif // GDAL_PIXEL_ACCESSOR_INCLUDED
Class to have reasonably fast random pixel access to a raster band, when accessing multiple pixels th...
Definition: gdalcachedpixelaccessor.h:53
bool Set(int nX, int nY, Type val)
Set the value of a pixel.
Definition: gdalcachedpixelaccessor.h:221
bool FlushCache()
Flush content of modified tiles and drop caches.
Definition: gdalcachedpixelaccessor.h:281
void SetBand(GDALRasterBand *poBand)
Assign the raster band if not known at construction time.
Definition: gdalcachedpixelaccessor.h:84
void ResetModifiedFlag()
Reset the modified flag for cached tiles.
Definition: gdalcachedpixelaccessor.h:302
Type Get(int nX, int nY, bool *pbSuccess=nullptr)
Get the value of a pixel.
Definition: gdalcachedpixelaccessor.h:148
~GDALCachedPixelAccessor()
Destructor.
Definition: gdalcachedpixelaccessor.h:129
A single raster band (or channel).
Definition: gdal_priv.h:1504
CPL error handling services.
#define CPLAssert(expr)
Assert on an expression.
Definition: cpl_error.h:225
void CPLDebug(const char *, const char *,...)
Display a debugging message.
Definition: cpl_error.cpp:747
short GInt16
Int16 type.
Definition: cpl_port.h:181
GIntBig GInt64
Signed 64 bit integer type.
Definition: cpl_port.h:236
unsigned int GUInt32
Unsigned int32 type.
Definition: cpl_port.h:177
GUIntBig GUInt64
Unsigned 64 bit integer type.
Definition: cpl_port.h:238
unsigned short GUInt16
Unsigned int16 type.
Definition: cpl_port.h:183
unsigned char GByte
Unsigned byte type.
Definition: cpl_port.h:185
int GInt32
Int32 type.
Definition: cpl_port.h:175
signed char GInt8
Signed int8 type.
Definition: cpl_port.h:187
GDALDataType
Definition: gdal.h:64
@ GDT_UInt32
Definition: gdal.h:70
@ GDT_UInt64
Definition: gdal.h:72
@ GDT_Int64
Definition: gdal.h:73
@ GDT_Byte
Definition: gdal.h:66
@ GDT_Int8
Definition: gdal.h:67
@ GDT_Float64
Definition: gdal.h:75
@ GDT_UInt16
Definition: gdal.h:68
@ GDT_Int16
Definition: gdal.h:69
@ GDT_Int32
Definition: gdal.h:71
@ GDT_Float32
Definition: gdal.h:74
@ GF_Write
Definition: gdal.h:134
@ GF_Read
Definition: gdal.h:133
C++ GDAL entry points.