1 /**********************************************************************
2  *
3  * Name:     gdalvirtualmem.cpp
4  * Project:  GDAL
5  * Purpose:  Dataset and rasterband exposed as a virtual memory mapping.
6  * Author:   Even Rouault, <even dot rouault at spatialys.com>
7  *
8  **********************************************************************
9  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys.com>
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  ****************************************************************************/
29 
30 #include "cpl_port.h"
31 #include "gdal.h"
32 #include "gdal_priv.h"
33 
34 #include <cstddef>
35 #include <cstring>
36 
37 #include <algorithm>
38 
39 #include "cpl_conv.h"
40 #include "cpl_error.h"
41 #include "cpl_virtualmem.h"
42 
43 // To be changed if we go to 64-bit RasterIO coordinates and spacing.
44 using coord_type = int;
45 using spacing_type = int;
46 
47 /************************************************************************/
48 /*                            GDALVirtualMem                            */
49 /************************************************************************/
50 
51 class GDALVirtualMem
52 {
53     GDALDatasetH hDS = nullptr;
54     GDALRasterBandH hBand = nullptr;
55     coord_type nXOff = 0;
56     coord_type nYOff = 0;
57     // int nXSize;
58     // int nYSize;
59     coord_type nBufXSize = 0;
60     coord_type nBufYSize = 0;
61     GDALDataType eBufType = GDT_Byte;
62     int nBandCount = 0;
63     int* panBandMap = nullptr;
64     int nPixelSpace = 0;
65     GIntBig nLineSpace = 0;
66     GIntBig nBandSpace = 0;
67 
68     bool bIsCompact = false;
69     bool bIsBandSequential = false;
70 
IsCompact() const71     bool IsCompact() const { return bIsCompact; }
IsBandSequential() const72     bool IsBandSequential() const { return bIsBandSequential; }
73 
74     void GetXYBand( size_t nOffset, coord_type& x, coord_type& y,
75                     int& band ) const;
76     size_t GetOffset( const coord_type& x, const coord_type& y, int band ) const;
77     bool GotoNextPixel( coord_type& x, coord_type& y, int& band ) const;
78 
79     void DoIOBandSequential( GDALRWFlag eRWFlag, size_t nOffset,
80                              void* pPage, size_t nBytes ) const;
81     void DoIOPixelInterleaved( GDALRWFlag eRWFlag, size_t nOffset,
82                                void* pPage, size_t nBytes ) const;
83 
84     CPL_DISALLOW_COPY_ASSIGN(GDALVirtualMem)
85 
86 public:
87              GDALVirtualMem( GDALDatasetH hDS,
88                              GDALRasterBandH hBand,
89                              const coord_type& nXOff,
90                              const coord_type& nYOff,
91                              const coord_type& nXSize,
92                              const coord_type& nYSize,
93                              const coord_type& nBufXSize,
94                              const coord_type& nBufYSize,
95                              GDALDataType eBufType,
96                              int nBandCount, const int* panBandMapIn,
97                              int nPixelSpace,
98                              GIntBig nLineSpace,
99                              GIntBig nBandSpace );
100             ~GDALVirtualMem();
101 
102     static void FillCacheBandSequential( CPLVirtualMem* ctxt,  size_t nOffset,
103                                          void* pPageToFill,
104                                          size_t nToFill, void* pUserData );
105     static void SaveFromCacheBandSequential( CPLVirtualMem* ctxt,
106                                              size_t nOffset,
107                                              const void* pPageToBeEvicted,
108                                              size_t nToEvicted,
109                                              void* pUserData );
110 
111     static void FillCachePixelInterleaved( CPLVirtualMem* ctxt, size_t nOffset,
112                                            void* pPageToFill,
113                                            size_t nToFill, void* pUserData );
114     static void SaveFromCachePixelInterleaved( CPLVirtualMem* ctxt,
115                                                size_t nOffset,
116                                                const void* pPageToBeEvicted,
117                                                size_t nToEvicted,
118                                                void* pUserData);
119 
120     static void Destroy(void* pUserData);
121 };
122 
123 /************************************************************************/
124 /*                             GDALVirtualMem()                         */
125 /************************************************************************/
126 
GDALVirtualMem(GDALDatasetH hDSIn,GDALRasterBandH hBandIn,const coord_type & nXOffIn,const coord_type & nYOffIn,const coord_type &,const coord_type &,const coord_type & nBufXSizeIn,const coord_type & nBufYSizeIn,GDALDataType eBufTypeIn,int nBandCountIn,const int * panBandMapIn,int nPixelSpaceIn,GIntBig nLineSpaceIn,GIntBig nBandSpaceIn)127 GDALVirtualMem::GDALVirtualMem( GDALDatasetH hDSIn,
128                                 GDALRasterBandH hBandIn,
129                                 const coord_type& nXOffIn,
130                                 const coord_type& nYOffIn,
131                                 const coord_type& /* nXSize */,
132                                 const coord_type& /* nYSize */,
133                                 const coord_type& nBufXSizeIn,
134                                 const coord_type& nBufYSizeIn,
135                                 GDALDataType eBufTypeIn,
136                                 int nBandCountIn, const int* panBandMapIn,
137                                 int nPixelSpaceIn,
138                                 GIntBig nLineSpaceIn,
139                                 GIntBig nBandSpaceIn ) :
140     hDS(hDSIn),
141     hBand(hBandIn),
142     nXOff(nXOffIn),
143     nYOff(nYOffIn),
144     // TODO(schwehr): Why not used or removed?
145     // nXSize(nXSize),
146     // nYSize(nYSize),
147     nBufXSize(nBufXSizeIn),
148     nBufYSize(nBufYSizeIn),
149     eBufType(eBufTypeIn),
150     nBandCount(nBandCountIn),
151     nPixelSpace(nPixelSpaceIn),
152     nLineSpace(nLineSpaceIn),
153     nBandSpace(nBandSpaceIn)
154 {
155     if( hDS != nullptr )
156     {
157         panBandMap = static_cast<int *>( CPLMalloc(nBandCount * sizeof(int)) );
158         if( panBandMapIn )
159         {
160             memcpy(panBandMap, panBandMapIn, nBandCount * sizeof(int));
161         }
162         else
163         {
164             for( int i = 0; i < nBandCount; i++ )
165                 panBandMap[i] = i + 1;
166         }
167     }
168     else
169     {
170         panBandMap = nullptr;
171         nBandCount = 1;
172     }
173 
174     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eBufType);
175     if( nPixelSpace == nDataTypeSize &&
176         nLineSpace == static_cast<GIntBig>(nBufXSize) * nPixelSpace &&
177         nBandSpace == nBufYSize * nLineSpace )
178         bIsCompact = true;
179     else if( nBandSpace == nDataTypeSize &&
180              nPixelSpace == nBandCount * nBandSpace &&
181              nLineSpace == static_cast<GIntBig>(nBufXSize) * nPixelSpace )
182         bIsCompact = true;
183     else
184         bIsCompact = false;
185 
186     bIsBandSequential = nBandSpace >= nBufYSize * nLineSpace;
187 }
188 
189 /************************************************************************/
190 /*                            ~GDALVirtualMem()                         */
191 /************************************************************************/
192 
~GDALVirtualMem()193 GDALVirtualMem::~GDALVirtualMem()
194 {
195     CPLFree(panBandMap);
196 }
197 
198 /************************************************************************/
199 /*                              GetXYBand()                             */
200 /************************************************************************/
201 
GetXYBand(size_t nOffset,coord_type & x,coord_type & y,int & band) const202 void GDALVirtualMem::GetXYBand( size_t nOffset, coord_type& x, coord_type& y,
203                                 int& band ) const
204 {
205     if( IsBandSequential() )
206     {
207         if( nBandCount == 1 )
208             band = 0;
209         else
210             band = static_cast<int>(nOffset / nBandSpace);
211         y = static_cast<coord_type>((nOffset - band * nBandSpace) / nLineSpace);
212         x = static_cast<coord_type>(
213             (nOffset - band * nBandSpace - y * nLineSpace) / nPixelSpace );
214     }
215     else
216     {
217         y = static_cast<coord_type>(nOffset / nLineSpace);
218         x = static_cast<coord_type>((nOffset - y * nLineSpace) / nPixelSpace);
219         if( nBandCount == 1 )
220             band = 0;
221         else
222             band = static_cast<int>(
223                 (nOffset - y * nLineSpace - x * nPixelSpace) / nBandSpace);
224     }
225 }
226 
227 /************************************************************************/
228 /*                            GotoNextPixel()                           */
229 /************************************************************************/
230 
GotoNextPixel(coord_type & x,coord_type & y,int & band) const231 bool GDALVirtualMem::GotoNextPixel( coord_type& x, coord_type& y,
232                                     int& band ) const
233 {
234     if( IsBandSequential() )
235     {
236         ++x;
237         if( x == nBufXSize )
238         {
239             x = 0;
240             ++y;
241         }
242         if( y == nBufYSize )
243         {
244             y = 0;
245             band ++;
246             if( band == nBandCount )
247                 return false;
248         }
249     }
250     else
251     {
252         band ++;
253         if( band == nBandCount )
254         {
255             band = 0;
256             ++x;
257         }
258         if( x == nBufXSize )
259         {
260             x = 0;
261             ++y;
262             if( y == nBufYSize )
263                 return false;
264         }
265     }
266     return true;
267 }
268 
269 /************************************************************************/
270 /*                              GetOffset()                             */
271 /************************************************************************/
272 
GetOffset(const coord_type & x,const coord_type & y,int band) const273 size_t GDALVirtualMem::GetOffset(const coord_type& x,
274                                  const coord_type& y, int band) const
275 {
276     return static_cast<size_t>(
277         x * nPixelSpace + y * nLineSpace + band * nBandSpace);
278 }
279 
280 /************************************************************************/
281 /*                          DoIOPixelInterleaved()                      */
282 /************************************************************************/
283 
DoIOPixelInterleaved(GDALRWFlag eRWFlag,const size_t nOffset,void * pPage,size_t nBytes) const284 void GDALVirtualMem::DoIOPixelInterleaved(
285     GDALRWFlag eRWFlag, const size_t nOffset, void* pPage, size_t nBytes ) const
286 {
287     coord_type x = 0;
288     coord_type y = 0;
289     int band = 0;
290 
291     GetXYBand(nOffset, x, y, band);
292 #ifdef DEBUG_VERBOSE
293     fprintf(stderr, "eRWFlag=%d, nOffset=%d, x=%d, y=%d, band=%d\n",/*ok*/
294             eRWFlag, static_cast<int>(nOffset), x, y, band);
295 #endif
296 
297     if( eRWFlag == GF_Read && !IsCompact() )
298         memset(pPage, 0, nBytes);
299 
300     if( band >= nBandCount )
301     {
302         band = nBandCount - 1;
303         if( !GotoNextPixel(x, y, band) )
304             return;
305     }
306     else if( x >= nBufXSize )
307     {
308         x = nBufXSize - 1;
309         band = nBandCount - 1;
310         if( !GotoNextPixel(x, y, band) )
311             return;
312     }
313 
314     size_t nOffsetRecompute = GetOffset(x, y, band);
315     CPLAssert(nOffsetRecompute >= nOffset);
316     size_t nOffsetShift = nOffsetRecompute - nOffset;
317     if( nOffsetShift >= nBytes )
318         return;
319 
320     // If we don't start at the first band for that given pixel, load/store
321     // the remaining bands
322     if( band > 0 )
323     {
324         size_t nEndOffsetEndOfPixel = GetOffset(x, y, nBandCount);
325         int bandEnd = nBandCount;
326         // Check that we have enough space to load/store until last band
327         // Should be always OK unless the number of bands is really huge
328         if( nEndOffsetEndOfPixel - nOffset > nBytes )
329         {
330             // Not enough space: find last possible band
331             coord_type xEnd, yEnd;
332             GetXYBand(nOffset + nBytes, xEnd, yEnd, bandEnd);
333             CPLAssert(x == xEnd);
334             CPLAssert(y == yEnd);
335         }
336 
337         // Finish reading/writing the remaining bands for that pixel
338         CPL_IGNORE_RET_VAL(GDALDatasetRasterIO(
339             hDS, eRWFlag,
340             nXOff + x, nYOff + y, 1, 1,
341             static_cast<char *>(pPage) + nOffsetShift,
342             1, 1, eBufType,
343             bandEnd - band, panBandMap + band,
344             nPixelSpace,
345             static_cast<spacing_type>(nLineSpace),
346             static_cast<spacing_type>(nBandSpace) ));
347 
348         if( bandEnd < nBandCount )
349             return;
350 
351         band = nBandCount - 1;
352         if( !GotoNextPixel(x, y, band) )
353             return;
354         nOffsetRecompute = GetOffset(x, y, 0);
355         nOffsetShift = nOffsetRecompute - nOffset;
356         if( nOffsetShift >= nBytes )
357             return;
358     }
359 
360     // Is there enough place to store/load up to the end of current line ?
361     size_t nEndOffsetEndOfLine = GetOffset(nBufXSize-1, y, nBandCount);
362     if( nEndOffsetEndOfLine - nOffset > nBytes )
363     {
364         // No : read/write as many pixels on this line as possible
365         coord_type xEnd, yEnd;
366         int bandEnd;
367         GetXYBand(nOffset + nBytes, xEnd, yEnd, bandEnd);
368         CPLAssert(y == yEnd);
369 
370         if( x < xEnd )
371         {
372             CPL_IGNORE_RET_VAL(GDALDatasetRasterIO(
373                 hDS, eRWFlag,
374                 nXOff + x, nYOff + y, xEnd - x, 1,
375                 static_cast<char *>(pPage) + nOffsetShift,
376                 xEnd - x, 1, eBufType,
377                 nBandCount, panBandMap,
378                 nPixelSpace,
379                 static_cast<spacing_type>(nLineSpace),
380                 static_cast<spacing_type>(nBandSpace) ));
381         }
382 
383         // Are there partial bands to read/write for the last pixel ?
384         if( bandEnd > 0 )
385         {
386             x = xEnd;
387             nOffsetRecompute = GetOffset(x, y, 0);
388             nOffsetShift = nOffsetRecompute - nOffset;
389             if( nOffsetShift >= nBytes )
390                 return;
391 
392             if( bandEnd >= nBandCount )
393                 bandEnd = nBandCount;
394 
395             CPL_IGNORE_RET_VAL(GDALDatasetRasterIO(
396                 hDS, eRWFlag,
397                 nXOff + x, nYOff + y, 1, 1,
398                 static_cast<char *>(pPage) + nOffsetShift,
399                 1, 1, eBufType,
400                 bandEnd, panBandMap,
401                 nPixelSpace,
402                 static_cast<spacing_type>(nLineSpace),
403                 static_cast<spacing_type>(nBandSpace) ));
404         }
405 
406         return;
407     }
408 
409     // Yes, enough place to read/write until end of line
410     if( x > 0 || nBytes - nOffsetShift < static_cast<size_t>(nLineSpace) )
411     {
412         CPL_IGNORE_RET_VAL(GDALDatasetRasterIO(
413             hDS, eRWFlag,
414             nXOff + x, nYOff + y, nBufXSize - x, 1,
415             static_cast<char *>(pPage) + nOffsetShift,
416             nBufXSize - x, 1, eBufType,
417             nBandCount, panBandMap,
418             nPixelSpace,
419             static_cast<spacing_type>(nLineSpace),
420             static_cast<spacing_type>(nBandSpace) ) );
421 
422         // Go to beginning of next line
423         x = nBufXSize - 1;
424         band = nBandCount - 1;
425         if( !GotoNextPixel(x, y, band) )
426             return;
427         nOffsetRecompute = GetOffset(x, y, 0);
428         nOffsetShift = nOffsetRecompute - nOffset;
429         if( nOffsetShift >= nBytes )
430             return;
431     }
432 
433     // How many whole lines can we store/load ?
434     coord_type nLineCount = static_cast<coord_type>((nBytes - nOffsetShift) / nLineSpace);
435     if( y + nLineCount > nBufYSize )
436         nLineCount = nBufYSize - y;
437     if( nLineCount > 0 )
438     {
439         CPL_IGNORE_RET_VAL(GDALDatasetRasterIO(
440             hDS, eRWFlag,
441             nXOff + 0, nYOff + y, nBufXSize, nLineCount,
442             static_cast<GByte *>(pPage) + nOffsetShift,
443             nBufXSize, nLineCount, eBufType,
444             nBandCount, panBandMap,
445             nPixelSpace,
446             static_cast<spacing_type>(nLineSpace),
447             static_cast<spacing_type>(nBandSpace) ) );
448 
449         y += nLineCount;
450         if( y == nBufYSize )
451             return;
452         nOffsetRecompute = GetOffset(x, y, 0);
453         nOffsetShift = nOffsetRecompute - nOffset;
454     }
455 
456     if( nOffsetShift < nBytes )
457     {
458         DoIOPixelInterleaved(
459             eRWFlag, nOffsetRecompute,
460             static_cast<char*>(pPage) + nOffsetShift,
461             nBytes - nOffsetShift );
462     }
463 }
464 
465 /************************************************************************/
466 /*                          DoIOPixelInterleaved()                      */
467 /************************************************************************/
468 
DoIOBandSequential(GDALRWFlag eRWFlag,const size_t nOffset,void * pPage,size_t nBytes) const469 void GDALVirtualMem::DoIOBandSequential(
470     GDALRWFlag eRWFlag, const size_t nOffset, void* pPage, size_t nBytes ) const
471 {
472     coord_type x = 0;
473     coord_type y = 0;
474 
475     int band = 0;
476     GetXYBand(nOffset, x, y, band);
477 #if DEBUG_VERBOSE
478     fprintf( stderr, "eRWFlag=%d, nOffset=%d, x=%d, y=%d, band=%d\n",/*ok*/
479              eRWFlag, static_cast<int>(nOffset), x, y, band );
480 #endif
481 
482     if( eRWFlag == GF_Read && !IsCompact() )
483         memset(pPage, 0, nBytes);
484 
485     if( x >= nBufXSize )
486     {
487         x = nBufXSize - 1;
488         if( !GotoNextPixel(x, y, band) )
489             return;
490     }
491     else if( y >= nBufYSize )
492     {
493         x = nBufXSize - 1;
494         y = nBufYSize - 1;
495         if( !GotoNextPixel(x, y, band) )
496             return;
497     }
498 
499     size_t nOffsetRecompute = GetOffset(x, y, band);
500     CPLAssert(nOffsetRecompute >= nOffset);
501     size_t nOffsetShift = nOffsetRecompute - nOffset;
502     if( nOffsetShift >= nBytes )
503         return;
504 
505     // Is there enough place to store/load up to the end of current line?
506     size_t nEndOffsetEndOfLine = GetOffset(nBufXSize, y, band);
507     if( nEndOffsetEndOfLine - nOffset > nBytes )
508     {
509         // No : read/write as many pixels on this line as possible
510         coord_type xEnd, yEnd;
511         int bandEnd;
512         GetXYBand(nOffset + nBytes, xEnd, yEnd, bandEnd);
513         CPLAssert(y == yEnd);
514         CPLAssert(band == bandEnd);
515         CPL_IGNORE_RET_VAL(GDALRasterIO(
516             hBand ? hBand : GDALGetRasterBand(hDS, panBandMap[band]),
517             eRWFlag,
518             nXOff + x, nYOff + y, xEnd - x, 1,
519             static_cast<char *>(pPage) + nOffsetShift,
520             xEnd - x, 1, eBufType,
521             nPixelSpace, static_cast<spacing_type>(nLineSpace) ));
522 
523         return;
524     }
525 
526     // Yes, enough place to read/write until end of line
527     if( x > 0 || nBytes - nOffsetShift < static_cast<size_t>(nLineSpace) )
528     {
529         CPL_IGNORE_RET_VAL(GDALRasterIO(
530             hBand ? hBand : GDALGetRasterBand(hDS, panBandMap[band]),
531             eRWFlag,
532                     nXOff + x, nYOff + y, nBufXSize - x, 1,
533                     static_cast<char *>(pPage) + nOffsetShift,
534                     nBufXSize - x, 1, eBufType,
535                     nPixelSpace, static_cast<spacing_type>(nLineSpace) ));
536 
537         // Go to beginning of next line
538         x = nBufXSize - 1;
539         if( !GotoNextPixel(x, y, band) )
540             return;
541         nOffsetRecompute = GetOffset(x, y, band);
542         nOffsetShift = nOffsetRecompute - nOffset;
543         if( nOffsetShift >= nBytes )
544             return;
545     }
546 
547     // How many whole lines can we store/load ?
548     coord_type nLineCount = static_cast<coord_type>((nBytes - nOffsetShift) / nLineSpace);
549     if( y + nLineCount > nBufYSize )
550         nLineCount = nBufYSize - y;
551     if( nLineCount > 0 )
552     {
553         CPL_IGNORE_RET_VAL(GDALRasterIO(
554             hBand ? hBand : GDALGetRasterBand(hDS, panBandMap[band]),
555             eRWFlag,
556             nXOff + 0, nYOff + y, nBufXSize, nLineCount,
557             static_cast<GByte *>(pPage) + nOffsetShift,
558             nBufXSize, nLineCount, eBufType,
559             nPixelSpace,
560             static_cast<spacing_type>(nLineSpace) ) );
561 
562         y += nLineCount;
563         if( y == nBufYSize )
564         {
565             y = 0;
566             band ++;
567             if( band == nBandCount )
568                 return;
569         }
570         nOffsetRecompute = GetOffset(x, y, band);
571         nOffsetShift = nOffsetRecompute - nOffset;
572     }
573 
574     if( nOffsetShift < nBytes )
575     {
576         DoIOBandSequential( eRWFlag, nOffsetRecompute,
577                static_cast<char*>(pPage) + nOffsetShift, nBytes - nOffsetShift );
578     }
579 }
580 
581 /************************************************************************/
582 /*                    FillCacheBandSequential()                        */
583 /************************************************************************/
584 
FillCacheBandSequential(CPLVirtualMem *,size_t nOffset,void * pPageToFill,size_t nToFill,void * pUserData)585 void GDALVirtualMem::FillCacheBandSequential(
586     CPLVirtualMem*,
587     size_t nOffset,
588     void* pPageToFill,
589     size_t nToFill,
590     void* pUserData )
591 {
592     const GDALVirtualMem* psParams = static_cast<GDALVirtualMem *>(pUserData);
593     psParams->DoIOBandSequential(GF_Read, nOffset, pPageToFill, nToFill);
594 }
595 
596 /************************************************************************/
597 /*                    SaveFromCacheBandSequential()                    */
598 /************************************************************************/
599 
SaveFromCacheBandSequential(CPLVirtualMem *,size_t nOffset,const void * pPageToBeEvicted,size_t nToEvicted,void * pUserData)600 void GDALVirtualMem::SaveFromCacheBandSequential(
601     CPLVirtualMem*,
602     size_t nOffset,
603     const void* pPageToBeEvicted,
604     size_t nToEvicted,
605     void* pUserData )
606 {
607     const GDALVirtualMem* psParams = static_cast<GDALVirtualMem *>(pUserData);
608     psParams->DoIOBandSequential(
609         GF_Write, nOffset, const_cast<void *>(pPageToBeEvicted), nToEvicted);
610 }
611 
612 /************************************************************************/
613 /*                     FillCachePixelInterleaved()                      */
614 /************************************************************************/
615 
FillCachePixelInterleaved(CPLVirtualMem *,size_t nOffset,void * pPageToFill,size_t nToFill,void * pUserData)616 void GDALVirtualMem::FillCachePixelInterleaved(
617     CPLVirtualMem*,
618     size_t nOffset,
619     void* pPageToFill,
620     size_t nToFill,
621     void* pUserData )
622 {
623     const GDALVirtualMem* psParams = static_cast<GDALVirtualMem *>(pUserData);
624     psParams->DoIOPixelInterleaved(GF_Read, nOffset, pPageToFill, nToFill);
625 }
626 
627 /************************************************************************/
628 /*                     SaveFromCachePixelInterleaved()                  */
629 /************************************************************************/
630 
SaveFromCachePixelInterleaved(CPLVirtualMem *,size_t nOffset,const void * pPageToBeEvicted,size_t nToEvicted,void * pUserData)631 void GDALVirtualMem::SaveFromCachePixelInterleaved(
632     CPLVirtualMem*,
633     size_t nOffset,
634     const void* pPageToBeEvicted,
635     size_t nToEvicted,
636     void* pUserData )
637 {
638     const GDALVirtualMem* psParams = static_cast<GDALVirtualMem *>(pUserData);
639     psParams->DoIOPixelInterleaved(
640         GF_Write, nOffset, const_cast<void *>(pPageToBeEvicted), nToEvicted);
641 }
642 
643 /************************************************************************/
644 /*                                Destroy()                             */
645 /************************************************************************/
646 
Destroy(void * pUserData)647 void GDALVirtualMem::Destroy(void* pUserData)
648 {
649     GDALVirtualMem* psParams = static_cast<GDALVirtualMem *>( pUserData );
650     delete psParams;
651 }
652 
653 /************************************************************************/
654 /*                      GDALCheckBandParameters()                       */
655 /************************************************************************/
656 
GDALCheckBandParameters(GDALDatasetH hDS,int nBandCount,int * panBandMap)657 static bool GDALCheckBandParameters( GDALDatasetH hDS,
658                                      int nBandCount, int* panBandMap )
659 {
660     if( nBandCount == 0 )
661     {
662         CPLError( CE_Failure, CPLE_AppDefined, "nBandCount == 0" );
663         return false;
664     }
665 
666     if( panBandMap != nullptr )
667     {
668         for( int i = 0; i < nBandCount; i++ )
669         {
670             if( panBandMap[i] < 1 || panBandMap[i] > GDALGetRasterCount(hDS) )
671             {
672                 CPLError( CE_Failure, CPLE_AppDefined, "panBandMap[%d]=%d",
673                           i, panBandMap[i] );
674                 return false;
675             }
676         }
677     }
678     else if( nBandCount > GDALGetRasterCount(hDS) )
679     {
680         CPLError( CE_Failure, CPLE_AppDefined,
681                  "nBandCount > GDALGetRasterCount(hDS)" );
682         return false;
683     }
684     return true;
685 }
686 
687 /************************************************************************/
688 /*                          GDALGetVirtualMem()                         */
689 /************************************************************************/
690 
GDALGetVirtualMem(GDALDatasetH hDS,GDALRasterBandH hBand,GDALRWFlag eRWFlag,coord_type nXOff,coord_type nYOff,coord_type nXSize,coord_type nYSize,coord_type nBufXSize,coord_type nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,int nPixelSpace,GIntBig nLineSpace,GIntBig nBandSpace,size_t nCacheSize,size_t nPageSizeHint,int bSingleThreadUsage,CSLConstList)691 static CPLVirtualMem* GDALGetVirtualMem( GDALDatasetH hDS,
692                                          GDALRasterBandH hBand,
693                                          GDALRWFlag eRWFlag,
694                                          coord_type nXOff, coord_type nYOff,
695                                          coord_type nXSize, coord_type nYSize,
696                                          coord_type nBufXSize,
697                                          coord_type nBufYSize,
698                                          GDALDataType eBufType,
699                                          int nBandCount, int* panBandMap,
700                                          int nPixelSpace,
701                                          GIntBig nLineSpace,
702                                          GIntBig nBandSpace,
703                                          size_t nCacheSize,
704                                          size_t nPageSizeHint,
705                                          int bSingleThreadUsage,
706                                          CSLConstList /*papszOptions*/ )
707 {
708     CPLVirtualMem* view = nullptr;
709     GDALVirtualMem* psParams = nullptr;
710     GUIntBig nReqMem = 0;
711 
712     if( nXSize != nBufXSize || nYSize != nBufYSize )
713     {
714         CPLError( CE_Failure, CPLE_NotSupported,
715                   "nXSize != nBufXSize || nYSize != nBufYSize" );
716         return nullptr;
717     }
718 
719     int nRasterXSize =
720         hDS ? GDALGetRasterXSize(hDS) : GDALGetRasterBandXSize(hBand);
721     int nRasterYSize =
722         hDS ? GDALGetRasterYSize(hDS) : GDALGetRasterBandYSize(hBand);
723 
724     if( nXOff < 0 || nYOff < 0 ||
725         nXSize == 0 || nYSize == 0 ||
726         nBufXSize < 0 || nBufYSize < 0 ||
727         nXOff + nXSize > nRasterXSize ||
728         nYOff + nYSize > nRasterYSize )
729     {
730         CPLError( CE_Failure, CPLE_AppDefined, "Invalid window request" );
731         return nullptr;
732     }
733 
734     if( nPixelSpace < 0 || nLineSpace < 0 || nBandSpace < 0)
735     {
736         CPLError( CE_Failure, CPLE_NotSupported,
737                   "nPixelSpace < 0 || nLineSpace < 0 || nBandSpace < 0" );
738         return nullptr;
739     }
740 
741     if( hDS != nullptr && !GDALCheckBandParameters(hDS, nBandCount, panBandMap ) )
742         return nullptr;
743 
744     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eBufType);
745     if( nPixelSpace == 0 )
746         nPixelSpace = nDataTypeSize;
747     if( nLineSpace == 0 )
748         nLineSpace = static_cast<GIntBig>(nBufXSize) * nPixelSpace;
749     if( nBandSpace == 0 )
750         nBandSpace = static_cast<GIntBig>(nBufYSize) * nLineSpace;
751 
752     // OFFSET = offset(x,y,band) = x * nPixelSpace + y * nLineSpace + band *
753     // nBandSpace where 0 <= x < nBufXSize and 0 <= y < nBufYSize and 0 <= band
754     // < nBandCount if nPixelSpace, nLineSpace and nBandSpace can have arbitrary
755     // values, there is no way of finding a unique(x,y,band) solution. We need
756     // to restrict the space of possibilities strongly.
757     // if nBandSpace >= nBufYSize * nLineSpace and
758     //   nLineSpace >= nBufXSize * nPixelSpace,           INTERLEAVE = BAND
759     //      band = OFFSET / nBandSpace
760     //      y = (OFFSET - band * nBandSpace) / nLineSpace
761     //      x = (OFFSET - band * nBandSpace - y * nLineSpace) / nPixelSpace
762     // else if nPixelSpace >= nBandCount * nBandSpace and
763     //   nLineSpace >= nBufXSize * nPixelSpace,    INTERLEAVE = PIXEL
764     //      y = OFFSET / nLineSpace
765     //      x = (OFFSET - y * nLineSpace) / nPixelSpace
766     //      band = (OFFSET - y * nLineSpace - x * nPixelSpace) / nBandSpace
767 
768     if( nDataTypeSize == 0 || /* to please Coverity. not needed */
769         nLineSpace < static_cast<GIntBig>(nBufXSize) * nPixelSpace ||
770         (nBandCount > 1 &&
771         (nBandSpace == nPixelSpace ||
772         (nBandSpace < nPixelSpace &&
773          (nBandSpace < nDataTypeSize ||
774           nPixelSpace < nBandCount * nBandSpace)) ||
775         (nBandSpace > nPixelSpace &&
776          (nPixelSpace < nDataTypeSize ||
777           nBandSpace < nBufYSize * nLineSpace)))) )
778     {
779         CPLError(
780             CE_Failure, CPLE_NotSupported,
781             "Only pixel interleaving or band interleaving are supported" );
782         return nullptr;
783     }
784 
785     /* Avoid odd spacings that would complicate I/O operations */
786     /* Ensuring they are multiple of nDataTypeSize should be fine, because */
787     /* the page size is a power of 2 that is also a multiple of nDataTypeSize */
788     if( (nPixelSpace % nDataTypeSize) != 0 ||
789         (nLineSpace % nDataTypeSize) != 0 ||
790         (nBandSpace % nDataTypeSize) != 0 )
791     {
792         CPLError( CE_Failure, CPLE_NotSupported,
793                   "Unsupported spacing" );
794         return nullptr;
795     }
796 
797     bool bIsBandSequential = nBandSpace >= nBufYSize * nLineSpace;
798     if( bIsBandSequential )
799         nReqMem = nBandCount * nBandSpace;
800     else
801         nReqMem = nBufYSize * nLineSpace;
802     if( nReqMem != static_cast<GUIntBig>(static_cast<size_t>(nReqMem)) )
803     {
804         CPLError( CE_Failure, CPLE_OutOfMemory,
805                   "Cannot reserve " CPL_FRMT_GUIB " bytes", nReqMem );
806         return nullptr;
807     }
808 
809     psParams = new GDALVirtualMem( hDS, hBand, nXOff, nYOff,
810                                    nXSize, nYSize,
811                                    nBufXSize, nBufYSize,
812                                    eBufType,
813                                    nBandCount, panBandMap,
814                                    nPixelSpace,
815                                    nLineSpace,
816                                    nBandSpace );
817 
818     view = CPLVirtualMemNew(
819         static_cast<size_t>(nReqMem),
820         nCacheSize,
821         nPageSizeHint,
822         bSingleThreadUsage,
823         eRWFlag == GF_Read ?
824         VIRTUALMEM_READONLY_ENFORCED : VIRTUALMEM_READWRITE,
825         bIsBandSequential ? GDALVirtualMem::FillCacheBandSequential :
826                             GDALVirtualMem::FillCachePixelInterleaved,
827         bIsBandSequential ? GDALVirtualMem::SaveFromCacheBandSequential :
828                             GDALVirtualMem::SaveFromCachePixelInterleaved,
829         GDALVirtualMem::Destroy,
830         psParams );
831 
832     if( view == nullptr )
833     {
834         delete psParams;
835     }
836 
837     return view;
838 }
839 
840 /************************************************************************/
841 /*                       GDALDatasetGetVirtualMem()                     */
842 /************************************************************************/
843 
844 /** Create a CPLVirtualMem object from a GDAL dataset object.
845  *
846  * Only supported on Linux for now.
847  *
848  * This method allows creating a virtual memory object for a region of one
849  * or more GDALRasterBands from  this dataset. The content of the virtual
850  * memory object is automatically filled from dataset content when a virtual
851  * memory page is first accessed, and it is released (or flushed in case of a
852  * "dirty" page) when the cache size limit has been reached.
853  *
854  * The pointer to access the virtual memory object is obtained with
855  * CPLVirtualMemGetAddr(). It remains valid until CPLVirtualMemFree() is called.
856  * CPLVirtualMemFree() must be called before the dataset object is destroyed.
857  *
858  * If p is such a pointer and base_type the C type matching eBufType, for
859  * default values of spacing parameters, the element of image coordinates (x, y)
860  * (relative to xOff, yOff) for band b can be accessed with
861  * ((base_type*)p)[x + y * nBufXSize + (b-1)*nBufXSize*nBufYSize].
862  *
863  * Note that the mechanism used to transparently fill memory pages when they are
864  * accessed is the same (but in a controlled way) than what occurs when a memory
865  * error occurs in a program. Debugging software will generally interrupt
866  * program execution when that happens. If needed, CPLVirtualMemPin() can be
867  * used to avoid that by ensuring memory pages are allocated before being
868  * accessed.
869  *
870  * The size of the region that can be mapped as a virtual memory object depends
871  * on hardware and operating system limitations.
872  * On Linux AMD64 platforms, the maximum value is 128 TB.
873  * On Linux x86 platforms, the maximum value is 2 GB.
874  *
875  * Data type translation is automatically done if the data type
876  * (eBufType) of the buffer is different than
877  * that of the GDALRasterBand.
878  *
879  * Image decimation / replication is currently not supported, i.e. if the
880  * size of the region being accessed (nXSize x nYSize) is different from the
881  * buffer size (nBufXSize x nBufYSize).
882  *
883  * The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
884  * writing from various organization of buffers. Arbitrary values for the
885  * spacing parameters are not supported. Those values must be multiple of the
886  * size of thebuffer data type, and must be either band sequential
887  * organization (typically nPixelSpace = GDALGetDataTypeSizeBytes(eBufType),
888  * nLineSpace = nPixelSpace * nBufXSize,
889  * nBandSpace = nLineSpace * nBufYSize), or pixel-interleaved organization
890  * (typically nPixelSpace = nBandSpace * nBandCount,
891  * nLineSpace = nPixelSpace * nBufXSize,
892  * nBandSpace = GDALGetDataTypeSizeBytes(eBufType))
893  *
894  * @param hDS Dataset object
895  *
896  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
897  * write a region of data.
898  *
899  * @param nXOff The pixel offset to the top left corner of the region
900  * of the band to be accessed.  This would be zero to start from the left side.
901  *
902  * @param nYOff The line offset to the top left corner of the region
903  * of the band to be accessed.  This would be zero to start from the top.
904  *
905  * @param nXSize The width of the region of the band to be accessed in pixels.
906  *
907  * @param nYSize The height of the region of the band to be accessed in lines.
908  *
909  * @param nBufXSize the width of the buffer image into which the desired region
910  * is to be read, or from which it is to be written.
911  *
912  * @param nBufYSize the height of the buffer image into which the desired
913  * region is to be read, or from which it is to be written.
914  *
915  * @param eBufType the type of the pixel values in the data buffer. The
916  * pixel values will automatically be translated to/from the GDALRasterBand
917  * data type as needed.
918  *
919  * @param nBandCount the number of bands being read or written.
920  *
921  * @param panBandMap the list of nBandCount band numbers being read/written.
922  * Note band numbers are 1 based. This may be NULL to select the first
923  * nBandCount bands.
924  *
925  * @param nPixelSpace The byte offset from the start of one pixel value in
926  * the buffer to the start of the next pixel value within a scanline. If
927  * defaulted (0) the size of the datatype eBufType is used.
928  *
929  * @param nLineSpace The byte offset from the start of one scanline in
930  * the buffer to the start of the next. If defaulted (0) the size of the
931  * datatype eBufType * nBufXSize is used.
932  *
933  * @param nBandSpace the byte offset from the start of one bands data to the
934  * start of the next. If defaulted (0) the value will be
935  * nLineSpace * nBufYSize implying band sequential organization
936  * of the data buffer.
937  *
938  * @param nCacheSize   size in bytes of the maximum memory that will be really
939  *                     allocated (must ideally fit into RAM)
940  *
941  * @param nPageSizeHint hint for the page size. Must be a multiple of the
942  *                      system page size, returned by CPLGetPageSize().
943  *                      Minimum value is generally 4096. Might be set to 0 to
944  *                      let the function determine a default page size.
945  *
946  * @param bSingleThreadUsage set to TRUE if there will be no concurrent threads
947  *                           that will access the virtual memory mapping. This
948  *                           can optimize performance a bit. If set to FALSE,
949  *                           CPLVirtualMemDeclareThread() must be called.
950  *
951  * @param papszOptions NULL terminated list of options. Unused for now.
952  *
953  * @return a virtual memory object that must be freed by CPLVirtualMemFree(),
954  *         or NULL in case of failure.
955  *
956  * @since GDAL 1.11
957  */
958 
GDALDatasetGetVirtualMem(GDALDatasetH hDS,GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,int nBufXSize,int nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,int nPixelSpace,GIntBig nLineSpace,GIntBig nBandSpace,size_t nCacheSize,size_t nPageSizeHint,int bSingleThreadUsage,CSLConstList papszOptions)959 CPLVirtualMem* GDALDatasetGetVirtualMem( GDALDatasetH hDS,
960                                          GDALRWFlag eRWFlag,
961                                          int nXOff, int nYOff,
962                                          int nXSize, int nYSize,
963                                          int nBufXSize, int nBufYSize,
964                                          GDALDataType eBufType,
965                                          int nBandCount, int* panBandMap,
966                                          int nPixelSpace,
967                                          GIntBig nLineSpace,
968                                          GIntBig nBandSpace,
969                                          size_t nCacheSize,
970                                          size_t nPageSizeHint,
971                                          int bSingleThreadUsage,
972                                          CSLConstList papszOptions )
973 {
974     return GDALGetVirtualMem( hDS, nullptr, eRWFlag, nXOff, nYOff, nXSize, nYSize,
975                               nBufXSize, nBufYSize, eBufType,
976                               nBandCount, panBandMap,
977                               nPixelSpace, nLineSpace, nBandSpace,
978                               nCacheSize, nPageSizeHint, bSingleThreadUsage,
979                               papszOptions );
980 }
981 
982 /************************************************************************/
983 /*                     GDALRasterBandGetVirtualMem()                    */
984 /************************************************************************/
985 
986 /** Create a CPLVirtualMem object from a GDAL raster band object.
987  *
988  * Only supported on Linux for now.
989  *
990  * This method allows creating a virtual memory object for a region of a
991  * GDALRasterBand. The content of the virtual
992  * memory object is automatically filled from dataset content when a virtual
993  * memory page is first accessed, and it is released (or flushed in case of a
994  * "dirty" page) when the cache size limit has been reached.
995  *
996  * The pointer to access the virtual memory object is obtained with
997  * CPLVirtualMemGetAddr(). It remains valid until CPLVirtualMemFree() is called.
998  * CPLVirtualMemFree() must be called before the raster band object is
999  * destroyed.
1000  *
1001  * If p is such a pointer and base_type the C type matching eBufType, for
1002  * values of spacing parameters, the element of image coordinates (x, y)
1003  * default (relative to xOff, yOff) can be accessed with
1004  * ((base_type*)p)[x + y * nBufXSize].
1005  *
1006  * Note that the mechanism used to transparently fill memory pages when they are
1007  * accessed is the same (but in a controlled way) than what occurs when a memory
1008  * error occurs in a program. Debugging software will generally interrupt
1009  * program execution when that happens. If needed, CPLVirtualMemPin() can be
1010  * used to avoid that by ensuring memory pages are allocated before being
1011  * accessed.
1012  *
1013  * The size of the region that can be mapped as a virtual memory object depends
1014  * on hardware and operating system limitations.
1015  * On Linux AMD64 platforms, the maximum value is 128 TB.
1016  * On Linux x86 platforms, the maximum value is 2 GB.
1017  *
1018  * Data type translation is automatically done if the data type
1019  * (eBufType) of the buffer is different than
1020  * that of the GDALRasterBand.
1021  *
1022  * Image decimation / replication is currently not supported, i.e. if the
1023  * size of the region being accessed (nXSize x nYSize) is different from the
1024  * buffer size (nBufXSize x nBufYSize).
1025  *
1026  * The nPixelSpace and nLineSpace parameters allow reading into or
1027  * writing from various organization of buffers. Arbitrary values for the
1028  * spacing parameters are not supported. Those values must be multiple of the
1029  * size of the buffer data type and must be such that nLineSpace >=
1030  * nPixelSpace * nBufXSize.
1031  *
1032  * @param hBand Rasterband object
1033  *
1034  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
1035  * write a region of data.
1036  *
1037  * @param nXOff The pixel offset to the top left corner of the region
1038  * of the band to be accessed.  This would be zero to start from the left side.
1039  *
1040  * @param nYOff The line offset to the top left corner of the region
1041  * of the band to be accessed.  This would be zero to start from the top.
1042  *
1043  * @param nXSize The width of the region of the band to be accessed in pixels.
1044  *
1045  * @param nYSize The height of the region of the band to be accessed in lines.
1046  *
1047  * @param nBufXSize the width of the buffer image into which the desired region
1048  * is to be read, or from which it is to be written.
1049  *
1050  * @param nBufYSize the height of the buffer image into which the desired
1051  * region is to be read, or from which it is to be written.
1052  *
1053  * @param eBufType the type of the pixel values in the data buffer. The
1054  * pixel values will automatically be translated to/from the GDALRasterBand
1055  * data type as needed.
1056  *
1057  * @param nPixelSpace The byte offset from the start of one pixel value in the
1058  * buffer to the start of the next pixel value within a scanline. If defaulted
1059  * (0) the size of the datatype eBufType is used.
1060  *
1061  * @param nLineSpace The byte offset from the start of one scanline in the
1062  * buffer to the start of the next. If defaulted (0) the size of the datatype
1063  * eBufType * nBufXSize is used.
1064  *
1065  * @param nCacheSize   size in bytes of the maximum memory that will be really
1066  *                     allocated (must ideally fit into RAM)
1067  *
1068  * @param nPageSizeHint hint for the page size. Must be a multiple of the
1069  *                      system page size, returned by CPLGetPageSize().
1070  *                      Minimum value is generally 4096. Might be set to 0 to
1071  *                      let the function determine a default page size.
1072  *
1073  * @param bSingleThreadUsage set to TRUE if there will be no concurrent threads
1074  *                           that will access the virtual memory mapping. This
1075  *                           can optimize performance a bit. If set to FALSE,
1076  *                           CPLVirtualMemDeclareThread() must be called.
1077  *
1078  * @param papszOptions NULL terminated list of options. Unused for now.
1079  *
1080  * @return a virtual memory object that must be freed by CPLVirtualMemFree(),
1081  *         or NULL in case of failure.
1082  *
1083  * @since GDAL 1.11
1084  */
1085 
GDALRasterBandGetVirtualMem(GDALRasterBandH hBand,GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,int nBufXSize,int nBufYSize,GDALDataType eBufType,int nPixelSpace,GIntBig nLineSpace,size_t nCacheSize,size_t nPageSizeHint,int bSingleThreadUsage,CSLConstList papszOptions)1086 CPLVirtualMem* GDALRasterBandGetVirtualMem( GDALRasterBandH hBand,
1087                                             GDALRWFlag eRWFlag,
1088                                             int nXOff, int nYOff,
1089                                             int nXSize, int nYSize,
1090                                             int nBufXSize, int nBufYSize,
1091                                             GDALDataType eBufType,
1092                                             int nPixelSpace,
1093                                             GIntBig nLineSpace,
1094                                             size_t nCacheSize,
1095                                             size_t nPageSizeHint,
1096                                             int bSingleThreadUsage,
1097                                             CSLConstList papszOptions )
1098 {
1099     return GDALGetVirtualMem( nullptr, hBand, eRWFlag, nXOff, nYOff,
1100                               nXSize, nYSize,
1101                               nBufXSize, nBufYSize, eBufType,
1102                               1, nullptr,
1103                               nPixelSpace, nLineSpace, 0,
1104                               nCacheSize, nPageSizeHint, bSingleThreadUsage,
1105                               papszOptions );
1106 }
1107 
1108 /************************************************************************/
1109 /*                        GDALTiledVirtualMem                           */
1110 /************************************************************************/
1111 
1112 class GDALTiledVirtualMem
1113 {
1114     GDALDatasetH hDS = nullptr;
1115     GDALRasterBandH hBand = nullptr;
1116     int nXOff = 0;
1117     int nYOff = 0;
1118     int nXSize = 0;
1119     int nYSize = 0;
1120     int nTileXSize = 0;
1121     int nTileYSize = 0;
1122     GDALDataType eBufType = GDT_Byte;
1123     int nBandCount = 0;
1124     int* panBandMap = nullptr;
1125     GDALTileOrganization eTileOrganization = GTO_TIP;
1126 
1127     void DoIO( GDALRWFlag eRWFlag, size_t nOffset,
1128                void* pPage, size_t nBytes ) const;
1129 
1130     CPL_DISALLOW_COPY_ASSIGN(GDALTiledVirtualMem)
1131 
1132 public:
1133              GDALTiledVirtualMem( GDALDatasetH hDS,
1134                                   GDALRasterBandH hBand,
1135                                   int nXOff, int nYOff,
1136                                   int nXSize, int nYSize,
1137                                   int nTileXSize, int nTileYSize,
1138                                   GDALDataType eBufType,
1139                                   int nBandCount, const int* panBandMapIn,
1140                                   GDALTileOrganization eTileOrganization );
1141             ~GDALTiledVirtualMem();
1142 
1143     static void FillCache( CPLVirtualMem* ctxt,  size_t nOffset,
1144                            void* pPageToFill,
1145                            size_t nPageSize, void* pUserData );
1146     static void SaveFromCache( CPLVirtualMem* ctxt,  size_t nOffset,
1147                                const void* pPageToBeEvicted,
1148                                size_t nToEvicted, void* pUserData );
1149 
1150     static void Destroy( void* pUserData );
1151 };
1152 
1153 /************************************************************************/
1154 /*                        GDALTiledVirtualMem()                         */
1155 /************************************************************************/
1156 
GDALTiledVirtualMem(GDALDatasetH hDSIn,GDALRasterBandH hBandIn,int nXOffIn,int nYOffIn,int nXSizeIn,int nYSizeIn,int nTileXSizeIn,int nTileYSizeIn,GDALDataType eBufTypeIn,int nBandCountIn,const int * panBandMapIn,GDALTileOrganization eTileOrganizationIn)1157 GDALTiledVirtualMem::GDALTiledVirtualMem(
1158     GDALDatasetH hDSIn,
1159     GDALRasterBandH hBandIn,
1160     int nXOffIn, int nYOffIn,
1161     int nXSizeIn, int nYSizeIn,
1162     int nTileXSizeIn, int nTileYSizeIn,
1163     GDALDataType eBufTypeIn,
1164     int nBandCountIn, const int* panBandMapIn,
1165     GDALTileOrganization eTileOrganizationIn ) :
1166     hDS(hDSIn),
1167     hBand(hBandIn),
1168     nXOff(nXOffIn),
1169     nYOff(nYOffIn),
1170     nXSize(nXSizeIn),
1171     nYSize(nYSizeIn),
1172     nTileXSize(nTileXSizeIn),
1173     nTileYSize(nTileYSizeIn),
1174     eBufType(eBufTypeIn),
1175     nBandCount(nBandCountIn),
1176     eTileOrganization(eTileOrganizationIn)
1177 {
1178     if( hDS != nullptr )
1179     {
1180         panBandMap = static_cast<int*>(CPLMalloc(nBandCount * sizeof(int)));
1181         if( panBandMapIn )
1182         {
1183             memcpy(panBandMap, panBandMapIn, nBandCount * sizeof(int));
1184         }
1185         else
1186         {
1187             for(int i = 0; i < nBandCount; i++ )
1188                 panBandMap[i] = i + 1;
1189         }
1190     }
1191     else
1192     {
1193         panBandMap = nullptr;
1194         nBandCount = 1;
1195     }
1196 }
1197 
1198 /************************************************************************/
1199 /*                       ~GDALTiledVirtualMem()                         */
1200 /************************************************************************/
1201 
~GDALTiledVirtualMem()1202 GDALTiledVirtualMem::~GDALTiledVirtualMem()
1203 {
1204     CPLFree(panBandMap);
1205 }
1206 
1207 /************************************************************************/
1208 /*                                DoIO()                                */
1209 /************************************************************************/
1210 
DoIO(GDALRWFlag eRWFlag,size_t nOffset,void * pPage,size_t nBytes) const1211 void GDALTiledVirtualMem::DoIO( GDALRWFlag eRWFlag, size_t nOffset,
1212                                 void* pPage, size_t nBytes ) const
1213 {
1214     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eBufType);
1215     int nTilesPerRow = (nXSize + nTileXSize - 1) / nTileXSize;
1216     int nTilesPerCol = (nYSize + nTileYSize - 1) / nTileYSize;
1217     size_t nPageSize = nTileXSize * nTileYSize * nDataTypeSize;
1218     if( eTileOrganization != GTO_BSQ )
1219         nPageSize *= nBandCount;
1220     CPLAssert((nOffset % nPageSize) == 0);
1221     CPLAssert(nBytes == nPageSize);
1222     size_t nTile = 0;
1223     int band = 0;
1224     int nPixelSpace = 0;
1225     int nLineSpace = 0;
1226     int nBandSpace = 0;
1227     if( eTileOrganization == GTO_TIP )
1228     {
1229         nTile = nOffset / nPageSize;
1230         band = 0;
1231         nPixelSpace = nDataTypeSize * nBandCount;
1232         nLineSpace = nPixelSpace * nTileXSize;
1233         nBandSpace = nDataTypeSize;
1234     }
1235     else if( eTileOrganization == GTO_BIT )
1236     {
1237         nTile = nOffset / nPageSize;
1238         band = 0;
1239         nPixelSpace = nDataTypeSize;
1240         nLineSpace = nPixelSpace * nTileXSize;
1241         nBandSpace = nLineSpace * nTileYSize;
1242     }
1243     else
1244     {
1245         // offset = nPageSize * (band * nTilesPerRow * nTilesPerCol + nTile)
1246         band = static_cast<int>(
1247             nOffset / (nPageSize * nTilesPerRow * nTilesPerCol));
1248         nTile = nOffset / nPageSize - band * nTilesPerRow * nTilesPerCol;
1249         nPixelSpace = nDataTypeSize;
1250         nLineSpace = nPixelSpace * nTileXSize;
1251         nBandSpace = 0;
1252         band ++;
1253     }
1254     size_t nYTile = nTile / nTilesPerRow;
1255     size_t nXTile = nTile - nYTile * nTilesPerRow;
1256 
1257     int nReqXSize = std::min( nTileXSize,
1258                               nXSize - static_cast<int>(nXTile * nTileXSize) );
1259     int nReqYSize = std::min( nTileYSize,
1260                               nYSize - static_cast<int>(nYTile * nTileYSize) );
1261     if( eRWFlag == GF_Read && (nReqXSize < nTileXSize ||
1262                                nReqYSize < nTileYSize) )
1263         memset(pPage, 0, nBytes);
1264     if( hDS != nullptr )
1265     {
1266         CPL_IGNORE_RET_VAL(GDALDatasetRasterIO(
1267             hDS, eRWFlag,
1268             static_cast<int>(nXOff + nXTile * nTileXSize),
1269             static_cast<int>(nYOff + nYTile * nTileYSize),
1270             nReqXSize, nReqYSize,
1271             pPage,
1272             nReqXSize, nReqYSize,
1273             eBufType,
1274             eTileOrganization != GTO_BSQ ? nBandCount : 1,
1275             eTileOrganization != GTO_BSQ ? panBandMap : &band,
1276             nPixelSpace, nLineSpace, nBandSpace ));
1277     }
1278     else
1279     {
1280         CPL_IGNORE_RET_VAL( GDALRasterIO(
1281             hBand, eRWFlag,
1282             static_cast<int>(nXOff + nXTile * nTileXSize),
1283             static_cast<int>(nYOff + nYTile * nTileYSize),
1284             nReqXSize, nReqYSize,
1285             pPage,
1286             nReqXSize, nReqYSize,
1287             eBufType,
1288             nPixelSpace, nLineSpace ) );
1289     }
1290 }
1291 
1292 /************************************************************************/
1293 /*                           FillCache()                                */
1294 /************************************************************************/
1295 
FillCache(CPLVirtualMem *,size_t nOffset,void * pPageToFill,size_t nToFill,void * pUserData)1296 void GDALTiledVirtualMem::FillCache( CPLVirtualMem*,
1297                                      size_t nOffset,
1298                                      void* pPageToFill,
1299                                      size_t nToFill,
1300                                      void* pUserData)
1301 {
1302     const GDALTiledVirtualMem* psParams =
1303         static_cast<GDALTiledVirtualMem *>( pUserData );
1304     psParams->DoIO(GF_Read, nOffset, pPageToFill, nToFill);
1305 }
1306 
1307 /************************************************************************/
1308 /*                          SaveFromCache()                             */
1309 /************************************************************************/
1310 
SaveFromCache(CPLVirtualMem *,size_t nOffset,const void * pPageToBeEvicted,size_t nToEvicted,void * pUserData)1311 void GDALTiledVirtualMem::SaveFromCache( CPLVirtualMem*,
1312                                          size_t nOffset,
1313                                          const void* pPageToBeEvicted,
1314                                          size_t nToEvicted, void* pUserData)
1315 {
1316     const GDALTiledVirtualMem* psParams =
1317         static_cast<GDALTiledVirtualMem *>( pUserData );
1318     psParams->DoIO( GF_Write, nOffset,
1319                    const_cast<void *>(pPageToBeEvicted),
1320                    nToEvicted );
1321 }
1322 
1323 /************************************************************************/
1324 /*                                Destroy()                             */
1325 /************************************************************************/
1326 
Destroy(void * pUserData)1327 void GDALTiledVirtualMem::Destroy( void* pUserData )
1328 {
1329     GDALTiledVirtualMem* psParams =
1330         static_cast<GDALTiledVirtualMem*>( pUserData );
1331     delete psParams;
1332 }
1333 
1334 /************************************************************************/
1335 /*                      GDALGetTiledVirtualMem()                        */
1336 /************************************************************************/
1337 
GDALGetTiledVirtualMem(GDALDatasetH hDS,GDALRasterBandH hBand,GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,int nTileXSize,int nTileYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,GDALTileOrganization eTileOrganization,size_t nCacheSize,int bSingleThreadUsage,CSLConstList)1338 static CPLVirtualMem* GDALGetTiledVirtualMem(
1339     GDALDatasetH hDS,
1340     GDALRasterBandH hBand,
1341     GDALRWFlag eRWFlag,
1342     int nXOff, int nYOff,
1343     int nXSize, int nYSize,
1344     int nTileXSize, int nTileYSize,
1345     GDALDataType eBufType,
1346     int nBandCount, int* panBandMap,
1347     GDALTileOrganization eTileOrganization,
1348     size_t nCacheSize,
1349     int bSingleThreadUsage,
1350     CSLConstList /* papszOptions */ )
1351 {
1352     CPLVirtualMem* view;
1353     GDALTiledVirtualMem* psParams;
1354 
1355     size_t nPageSize = CPLGetPageSize();
1356     if( nPageSize == 0 )
1357     {
1358         CPLError(
1359             CE_Failure, CPLE_NotSupported,
1360             "GDALGetTiledVirtualMem() unsupported on this "
1361             "operating system / configuration" );
1362         return nullptr;
1363     }
1364 
1365     int nRasterXSize =
1366         hDS ? GDALGetRasterXSize(hDS) : GDALGetRasterBandXSize(hBand);
1367     int nRasterYSize =
1368         hDS ? GDALGetRasterYSize(hDS) : GDALGetRasterBandYSize(hBand);
1369 
1370     if( nXOff < 0 || nYOff < 0 ||
1371         nTileXSize <= 0 || nTileYSize <= 0 ||
1372         nXOff + nXSize > nRasterXSize ||
1373         nYOff + nYSize > nRasterYSize )
1374     {
1375         CPLError(CE_Failure, CPLE_AppDefined, "Invalid window request");
1376         return nullptr;
1377     }
1378 
1379     if( hDS != nullptr && !GDALCheckBandParameters(hDS, nBandCount, panBandMap ) )
1380         return nullptr;
1381 
1382     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eBufType);
1383     int nTilesPerRow = (nXSize + nTileXSize - 1) / nTileXSize;
1384     int nTilesPerCol = (nYSize + nTileYSize - 1) / nTileYSize;
1385     GUIntBig nReqMem = static_cast<GUIntBig>(nTilesPerRow) * nTilesPerCol *
1386                         nTileXSize * nTileYSize * nBandCount * nDataTypeSize;
1387     if( nReqMem != static_cast<GUIntBig>(static_cast<size_t>(nReqMem)) )
1388     {
1389         CPLError( CE_Failure, CPLE_OutOfMemory,
1390                   "Cannot reserve " CPL_FRMT_GUIB " bytes", nReqMem );
1391         return nullptr;
1392     }
1393 
1394     size_t nPageSizeHint = nTileXSize * nTileYSize * nDataTypeSize;
1395     if( eTileOrganization != GTO_BSQ )
1396         nPageSizeHint *= nBandCount;
1397     if( (nPageSizeHint % nPageSize) != 0 )
1398     {
1399         CPLError( CE_Failure, CPLE_AppDefined,
1400                   "Tile dimensions incompatible with page size");
1401         return nullptr;
1402     }
1403 
1404     psParams = new GDALTiledVirtualMem( hDS, hBand, nXOff, nYOff,
1405                                         nXSize, nYSize,
1406                                         nTileXSize, nTileYSize,
1407                                         eBufType,
1408                                         nBandCount, panBandMap,
1409                                         eTileOrganization );
1410 
1411     view = CPLVirtualMemNew(
1412         static_cast<size_t>(nReqMem),
1413         nCacheSize,
1414         nPageSizeHint,
1415         bSingleThreadUsage,
1416         eRWFlag == GF_Read ?
1417         VIRTUALMEM_READONLY_ENFORCED : VIRTUALMEM_READWRITE,
1418         GDALTiledVirtualMem::FillCache,
1419         GDALTiledVirtualMem::SaveFromCache,
1420         GDALTiledVirtualMem::Destroy,
1421         psParams );
1422 
1423     if( view == nullptr )
1424     {
1425         delete psParams;
1426     }
1427     else if( CPLVirtualMemGetPageSize(view) != nPageSizeHint )
1428     {
1429         CPLError(
1430             CE_Failure, CPLE_AppDefined,
1431             "Did not get expected page size : %d vs %d",
1432             static_cast<int>(CPLVirtualMemGetPageSize(view)),
1433             static_cast<int>(nPageSizeHint) );
1434         CPLVirtualMemFree(view);
1435         return nullptr;
1436     }
1437 
1438     return view;
1439 }
1440 
1441 /************************************************************************/
1442 /*                   GDALDatasetGetTiledVirtualMem()                    */
1443 /************************************************************************/
1444 
1445 /** Create a CPLVirtualMem object from a GDAL dataset object, with tiling
1446  * organization
1447  *
1448  * Only supported on Linux for now.
1449  *
1450  * This method allows creating a virtual memory object for a region of one
1451  * or more GDALRasterBands from  this dataset. The content of the virtual
1452  * memory object is automatically filled from dataset content when a virtual
1453  * memory page is first accessed, and it is released (or flushed in case of a
1454  * "dirty" page) when the cache size limit has been reached.
1455  *
1456  * Contrary to GDALDatasetGetVirtualMem(), pixels will be organized by tiles
1457  * instead of scanlines. Different ways of organizing pixel within/across tiles
1458  * can be selected with the eTileOrganization parameter.
1459  *
1460  * If nXSize is not a multiple of nTileXSize or nYSize is not a multiple of
1461  * nTileYSize, partial tiles will exists at the right and/or bottom of the
1462  * region of interest. Those partial tiles will also have nTileXSize *
1463  * nTileYSize dimension, with padding pixels.
1464  *
1465  * The pointer to access the virtual memory object is obtained with
1466  * CPLVirtualMemGetAddr(). It remains valid until CPLVirtualMemFree() is called.
1467  * CPLVirtualMemFree() must be called before the dataset object is destroyed.
1468  *
1469  * If p is such a pointer and base_type the C type matching eBufType, for
1470  * default values of spacing parameters, the element of image coordinates (x, y)
1471  * (relative to xOff, yOff) for band b can be accessed with:
1472  *  - for eTileOrganization = GTO_TIP,
1473  *        ((base_type*)p)[tile_number(x,y)*nBandCount*tile_size +
1474  *                        offset_in_tile(x,y)*nBandCount + (b-1)].
1475  *  - for eTileOrganization = GTO_BIT,
1476  *        ((base_type*)p)[(tile_number(x,y)*nBandCount +
1477  *                        (b-1)) * tile_size + offset_in_tile(x,y)].
1478  *  - for eTileOrganization = GTO_BSQ,
1479  *        ((base_type*)p)[(tile_number(x,y) +
1480  *                        (b-1)*nTilesCount) * tile_size + offset_in_tile(x,y)].
1481  *
1482  * where nTilesPerRow = ceil(nXSize / nTileXSize)
1483  *       nTilesPerCol = ceil(nYSize / nTileYSize)
1484  *       nTilesCount = nTilesPerRow * nTilesPerCol
1485  *       tile_number(x,y) = (y / nTileYSize) * nTilesPerRow + (x / nTileXSize)
1486  *       offset_in_tile(x,y) = (y % nTileYSize) * nTileXSize  + (x % nTileXSize)
1487  *       tile_size = nTileXSize * nTileYSize
1488  *
1489  * Note that for a single band request, all tile organizations are equivalent.
1490  *
1491  * Note that the mechanism used to transparently fill memory pages when they are
1492  * accessed is the same (but in a controlled way) than what occurs when a memory
1493  * error occurs in a program. Debugging software will generally interrupt
1494  * program execution when that happens. If needed, CPLVirtualMemPin() can be
1495  * used to avoid that by ensuring memory pages are allocated before being
1496  * accessed.
1497  *
1498  * The size of the region that can be mapped as a virtual memory object depends
1499  * on hardware and operating system limitations.
1500  * On Linux AMD64 platforms, the maximum value is 128 TB.
1501  * On Linux x86 platforms, the maximum value is 2 GB.
1502  *
1503  * Data type translation is automatically done if the data type
1504  * (eBufType) of the buffer is different than
1505  * that of the GDALRasterBand.
1506  *
1507  * @param hDS Dataset object
1508  *
1509  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
1510  * write a region of data.
1511  *
1512  * @param nXOff The pixel offset to the top left corner of the region
1513  * of the band to be accessed.  This would be zero to start from the left side.
1514  *
1515  * @param nYOff The line offset to the top left corner of the region
1516  * of the band to be accessed.  This would be zero to start from the top.
1517  *
1518  * @param nXSize The width of the region of the band to be accessed in pixels.
1519  *
1520  * @param nYSize The height of the region of the band to be accessed in lines.
1521  *
1522  * @param nTileXSize the width of the tiles.
1523  *
1524  * @param nTileYSize the height of the tiles.
1525  *
1526  * @param eBufType the type of the pixel values in the data buffer. The
1527  * pixel values will automatically be translated to/from the GDALRasterBand
1528  * data type as needed.
1529  *
1530  * @param nBandCount the number of bands being read or written.
1531  *
1532  * @param panBandMap the list of nBandCount band numbers being read/written.
1533  * Note band numbers are 1 based. This may be NULL to select the first
1534  * nBandCount bands.
1535  *
1536  * @param eTileOrganization tile organization.
1537  *
1538  * @param nCacheSize   size in bytes of the maximum memory that will be really
1539  *                     allocated (must ideally fit into RAM)
1540  *
1541  * @param bSingleThreadUsage set to TRUE if there will be no concurrent threads
1542  *                           that will access the virtual memory mapping. This
1543  *                           can optimize performance a bit. If set to FALSE,
1544  *                           CPLVirtualMemDeclareThread() must be called.
1545  *
1546  * @param papszOptions NULL terminated list of options. Unused for now.
1547  *
1548  * @return a virtual memory object that must be freed by CPLVirtualMemFree(),
1549  *         or NULL in case of failure.
1550  *
1551  * @since GDAL 1.11
1552  */
1553 
GDALDatasetGetTiledVirtualMem(GDALDatasetH hDS,GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,int nTileXSize,int nTileYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,GDALTileOrganization eTileOrganization,size_t nCacheSize,int bSingleThreadUsage,CSLConstList papszOptions)1554 CPLVirtualMem* GDALDatasetGetTiledVirtualMem(
1555     GDALDatasetH hDS,
1556     GDALRWFlag eRWFlag,
1557     int nXOff, int nYOff,
1558     int nXSize, int nYSize,
1559     int nTileXSize, int nTileYSize,
1560     GDALDataType eBufType,
1561     int nBandCount, int* panBandMap,
1562     GDALTileOrganization eTileOrganization,
1563     size_t nCacheSize,
1564     int bSingleThreadUsage,
1565     CSLConstList papszOptions )
1566 {
1567     return GDALGetTiledVirtualMem( hDS, nullptr, eRWFlag, nXOff, nYOff,
1568                                    nXSize, nYSize, nTileXSize, nTileYSize,
1569                                    eBufType, nBandCount, panBandMap,
1570                                    eTileOrganization,
1571                                    nCacheSize, bSingleThreadUsage,
1572                                    papszOptions );
1573 }
1574 
1575 /************************************************************************/
1576 /*                   GDALRasterBandGetTiledVirtualMem()                 */
1577 /************************************************************************/
1578 
1579 /** Create a CPLVirtualMem object from a GDAL rasterband object, with tiling
1580  * organization
1581  *
1582  * Only supported on Linux for now.
1583  *
1584  * This method allows creating a virtual memory object for a region of one
1585  * GDALRasterBand. The content of the virtual
1586  * memory object is automatically filled from dataset content when a virtual
1587  * memory page is first accessed, and it is released (or flushed in case of a
1588  * "dirty" page) when the cache size limit has been reached.
1589  *
1590  * Contrary to GDALDatasetGetVirtualMem(), pixels will be organized by tiles
1591  * instead of scanlines.
1592  *
1593  * If nXSize is not a multiple of nTileXSize or nYSize is not a multiple of
1594  * nTileYSize, partial tiles will exists at the right and/or bottom of the
1595  * region of interest. Those partial tiles will also have nTileXSize *
1596  * nTileYSize dimension, with padding pixels.
1597  *
1598  * The pointer to access the virtual memory object is obtained with
1599  * CPLVirtualMemGetAddr(). It remains valid until CPLVirtualMemFree() is called.
1600  * CPLVirtualMemFree() must be called before the raster band object is
1601  * destroyed.
1602  *
1603  * If p is such a pointer and base_type the C type matching eBufType, for
1604  * default values of spacing parameters, the element of image coordinates (x, y)
1605  * (relative to xOff, yOff) can be accessed with:
1606  *  ((base_type*)p)[tile_number(x,y)*tile_size + offset_in_tile(x,y)].
1607  *
1608  * where nTilesPerRow = ceil(nXSize / nTileXSize)
1609  *       nTilesCount = nTilesPerRow * nTilesPerCol
1610  *       tile_number(x,y) = (y / nTileYSize) * nTilesPerRow + (x / nTileXSize)
1611  *       offset_in_tile(x,y) = (y % nTileYSize) * nTileXSize  + (x % nTileXSize)
1612  *       tile_size = nTileXSize * nTileYSize
1613  *
1614  * Note that the mechanism used to transparently fill memory pages when they are
1615  * accessed is the same (but in a controlled way) than what occurs when a memory
1616  * error occurs in a program. Debugging software will generally interrupt
1617  * program execution when that happens. If needed, CPLVirtualMemPin() can be
1618  * used to avoid that by ensuring memory pages are allocated before being
1619  * accessed.
1620  *
1621  * The size of the region that can be mapped as a virtual memory object depends
1622  * on hardware and operating system limitations.
1623  * On Linux AMD64 platforms, the maximum value is 128 TB.
1624  * On Linux x86 platforms, the maximum value is 2 GB.
1625  *
1626  * Data type translation is automatically done if the data type
1627  * (eBufType) of the buffer is different than
1628  * that of the GDALRasterBand.
1629  *
1630  * @param hBand Rasterband object
1631  *
1632  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
1633  * write a region of data.
1634  *
1635  * @param nXOff The pixel offset to the top left corner of the region
1636  * of the band to be accessed.  This would be zero to start from the left side.
1637  *
1638  * @param nYOff The line offset to the top left corner of the region
1639  * of the band to be accessed.  This would be zero to start from the top.
1640  *
1641  * @param nXSize The width of the region of the band to be accessed in pixels.
1642  *
1643  * @param nYSize The height of the region of the band to be accessed in lines.
1644  *
1645  * @param nTileXSize the width of the tiles.
1646  *
1647  * @param nTileYSize the height of the tiles.
1648  *
1649  * @param eBufType the type of the pixel values in the data buffer. The
1650  * pixel values will automatically be translated to/from the GDALRasterBand
1651  * data type as needed.
1652  *
1653  * @param nCacheSize   size in bytes of the maximum memory that will be really
1654  *                     allocated (must ideally fit into RAM)
1655  *
1656  * @param bSingleThreadUsage set to TRUE if there will be no concurrent threads
1657  *                           that will access the virtual memory mapping. This
1658  *                           can optimize performance a bit. If set to FALSE,
1659  *                           CPLVirtualMemDeclareThread() must be called.
1660  *
1661  * @param papszOptions NULL terminated list of options. Unused for now.
1662  *
1663  * @return a virtual memory object that must be freed by CPLVirtualMemFree(),
1664  *         or NULL in case of failure.
1665  *
1666  * @since GDAL 1.11
1667  */
1668 
GDALRasterBandGetTiledVirtualMem(GDALRasterBandH hBand,GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,int nTileXSize,int nTileYSize,GDALDataType eBufType,size_t nCacheSize,int bSingleThreadUsage,CSLConstList papszOptions)1669 CPLVirtualMem* GDALRasterBandGetTiledVirtualMem( GDALRasterBandH hBand,
1670                                                  GDALRWFlag eRWFlag,
1671                                                  int nXOff, int nYOff,
1672                                                  int nXSize, int nYSize,
1673                                                  int nTileXSize, int nTileYSize,
1674                                                  GDALDataType eBufType,
1675                                                  size_t nCacheSize,
1676                                                  int bSingleThreadUsage,
1677                                                  CSLConstList papszOptions )
1678 {
1679     return GDALGetTiledVirtualMem( nullptr, hBand, eRWFlag, nXOff, nYOff,
1680                                    nXSize, nYSize, nTileXSize, nTileYSize,
1681                                    eBufType, 1, nullptr,
1682                                    GTO_BSQ,
1683                                    nCacheSize, bSingleThreadUsage,
1684                                    papszOptions );
1685 }
1686