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  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
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>
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>
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>
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>
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>
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