diff --git a/frmts/vrt/vrtsources.cpp b/frmts/vrt/vrtsources.cpp index 26a5e468d58a..bc7a8f6b9a37 100644 --- a/frmts/vrt/vrtsources.cpp +++ b/frmts/vrt/vrtsources.cpp @@ -3080,6 +3080,52 @@ static inline bool hasZeroByte(uint32_t v) return (((v)-0x01010101U) & ~(v)&0x80808080U) != 0; } +/************************************************************************/ +/* CopyWord() */ +/************************************************************************/ + +template +static void CopyWord(const SrcType *pSrcVal, GDALDataType eSrcType, + void *pDstVal, GDALDataType eDstType) +{ + switch (eDstType) + { + case GDT_Byte: + GDALCopyWord(*pSrcVal, *static_cast(pDstVal)); + break; + case GDT_Int8: + GDALCopyWord(*pSrcVal, *static_cast(pDstVal)); + break; + case GDT_UInt16: + GDALCopyWord(*pSrcVal, *static_cast(pDstVal)); + break; + case GDT_Int16: + GDALCopyWord(*pSrcVal, *static_cast(pDstVal)); + break; + case GDT_UInt32: + GDALCopyWord(*pSrcVal, *static_cast(pDstVal)); + break; + case GDT_Int32: + GDALCopyWord(*pSrcVal, *static_cast(pDstVal)); + break; + case GDT_UInt64: + GDALCopyWord(*pSrcVal, *static_cast(pDstVal)); + break; + case GDT_Int64: + GDALCopyWord(*pSrcVal, *static_cast(pDstVal)); + break; + case GDT_Float32: + GDALCopyWord(*pSrcVal, *static_cast(pDstVal)); + break; + case GDT_Float64: + GDALCopyWord(*pSrcVal, *static_cast(pDstVal)); + break; + default: + GDALCopyWords(pSrcVal, eSrcType, 0, pDstVal, eDstType, 0, 1); + break; + } +} + /************************************************************************/ /* RasterIOProcessNoData() */ /************************************************************************/ @@ -3235,8 +3281,8 @@ CPLErr VRTComplexSource::RasterIOProcessNoData( { if (paSrcData[idxBuffer] != nNoDataValue) { - GDALCopyWords(&paSrcData[idxBuffer], eSourceType, 0, - pDstLocation, eBufType, 0, 1); + CopyWord(&paSrcData[idxBuffer], eSourceType, pDstLocation, + eBufType); } } } @@ -3256,8 +3302,8 @@ CPLErr VRTComplexSource::RasterIOProcessNoData( { // Convert first to the VRTRasterBand data type // to get its clamping, before outputting to buffer data type - GDALCopyWords(&paSrcData[idxBuffer], eSourceType, 0, - abyTemp, eVRTBandDataType, 0, 1); + CopyWord(&paSrcData[idxBuffer], eSourceType, abyTemp, + eVRTBandDataType); GDALCopyWords(abyTemp, eVRTBandDataType, 0, pDstLocation, eBufType, 0, 1); } @@ -3415,6 +3461,12 @@ CPLErr VRTComplexSource::RasterIOInternal( /* Selectively copy into output buffer with nodata masking, */ /* and/or scaling. */ /* -------------------------------------------------------------------- */ + + const bool bTwoStepDataTypeConversion = + CPL_TO_BOOL( + GDALDataTypeIsConversionLossy(eWrkDataType, eVRTBandDataType)) && + !CPL_TO_BOOL(GDALDataTypeIsConversionLossy(eVRTBandDataType, eBufType)); + size_t idxBuffer = 0; for (int iY = 0; iY < nOutYSize; iY++) { @@ -3551,18 +3603,28 @@ CPLErr VRTComplexSource::RasterIOInternal( 255.0f, std::max(0.0f, static_cast(afResult[0]) + 0.5f))); } - else if (eBufType == eVRTBandDataType) + else if (!bTwoStepDataTypeConversion) + { + CopyWord(afResult, eWrkDataType, pDstLocation, + eBufType); + } + else if (eVRTBandDataType == GDT_Float32 && eBufType == GDT_Float64) { - GDALCopyWords(afResult, eWrkDataType, 0, pDstLocation, eBufType, - 0, 1); + // Particular case of the below 2-step conversion. + // Helps a bit for some geolocation based warping with Sentinel3 + // data where the longitude/latitude arrays are Int32 bands, + // rescaled in VRT as Float32 and requested as Float64 + float fVal; + GDALCopyWord(afResult[0], fVal); + *reinterpret_cast(pDstLocation) = fVal; } else { GByte abyTemp[2 * sizeof(double)]; // Convert first to the VRTRasterBand data type // to get its clamping, before outputting to buffer data type - GDALCopyWords(afResult, eWrkDataType, 0, abyTemp, - eVRTBandDataType, 0, 1); + CopyWord(afResult, eWrkDataType, abyTemp, + eVRTBandDataType); GDALCopyWords(abyTemp, eVRTBandDataType, 0, pDstLocation, eBufType, 0, 1); }