LCOV - code coverage report
Current view: top level - gcore - gdalvirtualmem.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 372 452 82.3 %
Date: 2024-11-21 22:18:42 Functions: 25 27 92.6 %

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

Generated by: LCOV version 1.14