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 
77  GDALCachedPixelAccessor& operator= (const GDALCachedPixelAccessor&) = delete;
78 
79 public:
80  explicit GDALCachedPixelAccessor(GDALRasterBand* poBand);
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>
111 {
112 }
113 
114 /************************************************************************/
115 /* ~GDALCachedPixelAccessor() */
116 /************************************************************************/
117 
122 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
124 {
125  FlushCache();
126 }
127 
128 /************************************************************************/
129 /* Get() */
130 /************************************************************************/
131 
141 template<class Type, int TILE_SIZE, int CACHED_TILE_COUNT>
142 inline
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>
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
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>
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>
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>
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>
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>
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