@@ -982,6 +982,56 @@ CPLErr VRTDerivedRasterBand::GetPixelFunctionArguments(
982982 return CE_None;
983983}
984984
985+ /* ***********************************************************************/
986+ /* CreateMapBufferIdxToSourceIdx() */
987+ /* ***********************************************************************/
988+
989+ static bool CreateMapBufferIdxToSourceIdx (
990+ const std::vector<std::unique_ptr<VRTSource>> &apoSources,
991+ bool bSkipNonContributingSources, int nXOff, int nYOff, int nXSize,
992+ int nYSize, int nBufXSize, int nBufYSize, GDALRasterIOExtraArg *psExtraArg,
993+ bool &bCreateMapBufferIdxToSourceIdxHasRun,
994+ std::vector<int > &anMapBufferIdxToSourceIdx,
995+ bool &bSkipOutputBufferInitialization)
996+ {
997+ CPLAssert (!bCreateMapBufferIdxToSourceIdxHasRun);
998+ bCreateMapBufferIdxToSourceIdxHasRun = true ;
999+ anMapBufferIdxToSourceIdx.reserve (apoSources.size ());
1000+ for (int iSource = 0 ; iSource < static_cast <int >(apoSources.size ());
1001+ iSource++)
1002+ {
1003+ if (bSkipNonContributingSources &&
1004+ apoSources[iSource]->IsSimpleSource ())
1005+ {
1006+ bool bError = false ;
1007+ double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
1008+ int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
1009+ int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
1010+ auto poSource =
1011+ static_cast <VRTSimpleSource *>(apoSources[iSource].get ());
1012+ if (!poSource->GetSrcDstWindow (
1013+ nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
1014+ psExtraArg->eResampleAlg , &dfReqXOff, &dfReqYOff,
1015+ &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff, &nReqXSize,
1016+ &nReqYSize, &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize,
1017+ bError))
1018+ {
1019+ if (bError)
1020+ {
1021+ return false ;
1022+ }
1023+
1024+ // Skip non contributing source
1025+ bSkipOutputBufferInitialization = false ;
1026+ continue ;
1027+ }
1028+ }
1029+
1030+ anMapBufferIdxToSourceIdx.push_back (iSource);
1031+ }
1032+ return true ;
1033+ }
1034+
9851035/* ***********************************************************************/
9861036/* IRasterIO() */
9871037/* ***********************************************************************/
@@ -1142,6 +1192,10 @@ CPLErr VRTDerivedRasterBand::IRasterIO(
11421192 }
11431193 const int nSrcTypeSize = GDALGetDataTypeSizeBytes (eSrcType);
11441194
1195+ std::vector<int > anMapBufferIdxToSourceIdx;
1196+ bool bSkipOutputBufferInitialization = !m_papoSources.empty ();
1197+ bool bCreateMapBufferIdxToSourceIdxHasRun = false ;
1198+
11451199 // If acquiring the region of interest in a single time is going
11461200 // to consume too much RAM, split in halves, and that recursively
11471201 // until we get below m_nAllowedRAMUsage.
@@ -1151,11 +1205,34 @@ CPLErr VRTDerivedRasterBand::IRasterIO(
11511205 m_poPrivate->m_nAllowedRAMUsage /
11521206 (static_cast <int >(m_papoSources.size ()) * nSrcTypeSize))
11531207 {
1154- CPLErr eErr = SplitRasterIO (eRWFlag, nXOff, nYOff, nXSize, nYSize,
1155- pData, nBufXSize, nBufYSize, eBufType,
1156- nPixelSpace, nLineSpace, psExtraArg);
1157- if (eErr != CE_Warning)
1158- return eErr;
1208+ bool bSplit = true ;
1209+ if (m_poPrivate->m_bSkipNonContributingSources )
1210+ {
1211+ // More accurate check by comparing against the number of
1212+ // actually contributing sources.
1213+ if (!CreateMapBufferIdxToSourceIdx (
1214+ m_papoSources, m_poPrivate->m_bSkipNonContributingSources ,
1215+ nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
1216+ psExtraArg, bCreateMapBufferIdxToSourceIdxHasRun,
1217+ anMapBufferIdxToSourceIdx, bSkipOutputBufferInitialization))
1218+ {
1219+ return CE_Failure;
1220+ }
1221+ bSplit =
1222+ !anMapBufferIdxToSourceIdx.empty () &&
1223+ static_cast <GIntBig>(nBufXSize) * nBufYSize >
1224+ m_poPrivate->m_nAllowedRAMUsage /
1225+ (static_cast <int >(anMapBufferIdxToSourceIdx.size ()) *
1226+ nSrcTypeSize);
1227+ }
1228+ if (bSplit)
1229+ {
1230+ CPLErr eErr = SplitRasterIO (eRWFlag, nXOff, nYOff, nXSize, nYSize,
1231+ pData, nBufXSize, nBufYSize, eBufType,
1232+ nPixelSpace, nLineSpace, psExtraArg);
1233+ if (eErr != CE_Warning)
1234+ return eErr;
1235+ }
11591236 }
11601237
11611238 /* ---- Get pixel function for band ---- */
@@ -1196,51 +1273,32 @@ CPLErr VRTDerivedRasterBand::IRasterIO(
11961273 }
11971274 const int nExtBufXSize = nBufXSize + 2 * nBufferRadius;
11981275 const int nExtBufYSize = nBufYSize + 2 * nBufferRadius;
1199- int nBufferCount = 0 ;
12001276
1201- std::vector<std::unique_ptr<void , VSIFreeReleaser>> apBuffers (
1202- m_papoSources.size ());
1203- std::vector<int > anMapBufferIdxToSourceIdx (m_papoSources.size ());
1204- bool bSkipOutputBufferInitialization = !m_papoSources.empty ();
1205- for (int iSource = 0 ; iSource < static_cast <int >(m_papoSources.size ());
1206- iSource++)
1277+ if (!bCreateMapBufferIdxToSourceIdxHasRun)
12071278 {
1208- if (m_poPrivate->m_bSkipNonContributingSources &&
1209- m_papoSources[iSource]->IsSimpleSource ())
1279+ if (!CreateMapBufferIdxToSourceIdx (
1280+ m_papoSources, m_poPrivate->m_bSkipNonContributingSources ,
1281+ nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, psExtraArg,
1282+ bCreateMapBufferIdxToSourceIdxHasRun, anMapBufferIdxToSourceIdx,
1283+ bSkipOutputBufferInitialization))
12101284 {
1211- bool bError = false ;
1212- double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
1213- int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
1214- int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
1215- auto poSource =
1216- static_cast <VRTSimpleSource *>(m_papoSources[iSource].get ());
1217- if (!poSource->GetSrcDstWindow (
1218- nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
1219- psExtraArg->eResampleAlg , &dfReqXOff, &dfReqYOff,
1220- &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff, &nReqXSize,
1221- &nReqYSize, &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize,
1222- bError))
1223- {
1224- if (bError)
1225- {
1226- return CE_Failure;
1227- }
1228-
1229- // Skip non contributing source
1230- bSkipOutputBufferInitialization = false ;
1231- continue ;
1232- }
1285+ return CE_Failure;
12331286 }
1234-
1235- anMapBufferIdxToSourceIdx[nBufferCount] = iSource;
1236- apBuffers[nBufferCount].reset (
1287+ }
1288+ std::vector<std::unique_ptr<void , VSIFreeReleaser>> apBuffers (
1289+ anMapBufferIdxToSourceIdx.size ());
1290+ for (size_t iBuffer = 0 ; iBuffer < anMapBufferIdxToSourceIdx.size ();
1291+ ++iBuffer)
1292+ {
1293+ apBuffers[iBuffer].reset (
12371294 VSI_MALLOC3_VERBOSE (nSrcTypeSize, nExtBufXSize, nExtBufYSize));
1238- if (apBuffers[nBufferCount ] == nullptr )
1295+ if (apBuffers[iBuffer ] == nullptr )
12391296 {
12401297 return CE_Failure;
12411298 }
12421299
12431300 bool bBufferInit = true ;
1301+ const int iSource = anMapBufferIdxToSourceIdx[iBuffer];
12441302 if (m_papoSources[iSource]->IsSimpleSource ())
12451303 {
12461304 const auto poSS =
@@ -1279,53 +1337,36 @@ CPLErr VRTDerivedRasterBand::IRasterIO(
12791337 /* ------------------------------------------------------------ */
12801338 if (!m_bNoDataValueSet || m_dfNoDataValue == 0 )
12811339 {
1282- memset (apBuffers[nBufferCount ].get (), 0 ,
1340+ memset (apBuffers[iBuffer ].get (), 0 ,
12831341 static_cast <size_t >(nSrcTypeSize) * nExtBufXSize *
12841342 nExtBufYSize);
12851343 }
12861344 else
12871345 {
1288- GDALCopyWords64 (
1289- &m_dfNoDataValue, GDT_Float64, 0 ,
1290- static_cast <GByte *>(apBuffers[nBufferCount]. get ()) ,
1291- eSrcType, nSrcTypeSize,
1292- static_cast <GPtrDiff_t>(nExtBufXSize) * nExtBufYSize);
1346+ GDALCopyWords64 (&m_dfNoDataValue, GDT_Float64, 0 ,
1347+ static_cast <GByte *>(apBuffers[iBuffer]. get ()) ,
1348+ eSrcType, nSrcTypeSize ,
1349+ static_cast <GPtrDiff_t>(nExtBufXSize) *
1350+ nExtBufYSize);
12931351 }
12941352 }
1295-
1296- ++nBufferCount;
12971353 }
12981354
12991355 /* -------------------------------------------------------------------- */
13001356 /* Initialize the buffer to some background value. Use the */
13011357 /* nodata value if available. */
13021358 /* -------------------------------------------------------------------- */
1303- if (bSkipOutputBufferInitialization)
1304- {
1305- // Do nothing
1306- }
1307- else if (nPixelSpace == nBufTypeSize &&
1308- (!m_bNoDataValueSet || m_dfNoDataValue == 0 ))
1359+ if (!bSkipOutputBufferInitialization)
13091360 {
1310- memset (pData, 0 ,
1311- static_cast <size_t >(nBufXSize) * nBufYSize * nBufTypeSize);
1312- }
1313- else if (m_bNoDataValueSet)
1314- {
1315- double dfWriteValue = m_dfNoDataValue;
1316-
1317- for (int iLine = 0 ; iLine < nBufYSize; iLine++)
1318- {
1319- GDALCopyWords64 (&dfWriteValue, GDT_Float64, 0 ,
1320- static_cast <GByte *>(pData) + nLineSpace * iLine,
1321- eBufType, static_cast <int >(nPixelSpace), nBufXSize);
1322- }
1361+ InitializeOutputBuffer (pData, nBufXSize, nBufYSize, eBufType,
1362+ nPixelSpace, nLineSpace);
13231363 }
13241364
13251365 // No contributing sources and SkipNonContributingSources mode ?
13261366 // Do not call the pixel function and just return the 0/nodata initialized
13271367 // output buffer.
1328- if (nBufferCount == 0 && m_poPrivate->m_bSkipNonContributingSources )
1368+ if (anMapBufferIdxToSourceIdx.empty () &&
1369+ m_poPrivate->m_bSkipNonContributingSources )
13291370 {
13301371 return CE_None;
13311372 }
@@ -1400,7 +1441,9 @@ CPLErr VRTDerivedRasterBand::IRasterIO(
14001441 // Load values for sources into packed buffers.
14011442 CPLErr eErr = CE_None;
14021443 VRTSource::WorkingState oWorkingState;
1403- for (int iBuffer = 0 ; iBuffer < nBufferCount && eErr == CE_None; iBuffer++)
1444+ for (size_t iBuffer = 0 ;
1445+ iBuffer < anMapBufferIdxToSourceIdx.size () && eErr == CE_None;
1446+ iBuffer++)
14041447 {
14051448 const int iSource = anMapBufferIdxToSourceIdx[iBuffer];
14061449 GByte *pabyBuffer = static_cast <GByte *>(apBuffers[iBuffer].get ());
@@ -1486,6 +1529,7 @@ CPLErr VRTDerivedRasterBand::IRasterIO(
14861529 }
14871530
14881531 // Apply pixel function.
1532+ const int nBufferCount = static_cast <int >(anMapBufferIdxToSourceIdx.size ());
14891533 if (eErr == CE_None && EQUAL (m_poPrivate->m_osLanguage , " Python" ))
14901534 {
14911535 // numpy doesn't have native cint16/cint32/cfloat16
0 commit comments