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

Generated by: LCOV version 1.14