Skip to content

Commit

Permalink
Merge pull request #11612 from rouault/GDALExpandPackedBitsToByteAt0O…
Browse files Browse the repository at this point in the history
…r255

Add GDALExpandPackedBitsToByteAt0Or255() and GDALExpandPackedBitsToByteAt0Or1()
  • Loading branch information
rouault authored Jan 9, 2025
2 parents 6713bba + 4bb4f4c commit 4487cb9
Show file tree
Hide file tree
Showing 5 changed files with 285 additions and 140 deletions.
68 changes: 68 additions & 0 deletions autotest/cpp/test_gdal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5124,4 +5124,72 @@ TEST_F(test_gdal, GDALTranspose2D_Byte_optims)
}
}

TEST_F(test_gdal, GDALExpandPackedBitsToByteAt0Or1)
{
unsigned next = 1;
const auto badRand = [&next]()
{
next = static_cast<unsigned>(static_cast<uint64_t>(next) * 1103515245 +
12345);
return next;
};

constexpr int BITS_PER_BYTE = 8;
constexpr int SSE_REGISTER_SIZE_IN_BYTES = 16;
constexpr int LESS_THAN_8BITS = 5;
std::vector<GByte> expectedOut(SSE_REGISTER_SIZE_IN_BYTES * BITS_PER_BYTE +
BITS_PER_BYTE + LESS_THAN_8BITS);
std::vector<GByte> in((expectedOut.size() + BITS_PER_BYTE - 1) /
BITS_PER_BYTE);
for (int i = 0; i < static_cast<int>(expectedOut.size()); ++i)
{
expectedOut[i] = (badRand() % 2) == 0 ? 0 : 1;
if (expectedOut[i])
{
in[i / BITS_PER_BYTE] = static_cast<GByte>(
in[i / BITS_PER_BYTE] |
(1 << (BITS_PER_BYTE - 1 - (i % BITS_PER_BYTE))));
}
}

std::vector<GByte> out(expectedOut.size());
GDALExpandPackedBitsToByteAt0Or1(in.data(), out.data(), out.size());

EXPECT_EQ(out, expectedOut);
}

TEST_F(test_gdal, GDALExpandPackedBitsToByteAt0Or255)
{
unsigned next = 1;
const auto badRand = [&next]()
{
next = static_cast<unsigned>(static_cast<uint64_t>(next) * 1103515245 +
12345);
return next;
};

constexpr int BITS_PER_BYTE = 8;
constexpr int SSE_REGISTER_SIZE_IN_BYTES = 16;
constexpr int LESS_THAN_8BITS = 5;
std::vector<GByte> expectedOut(SSE_REGISTER_SIZE_IN_BYTES * BITS_PER_BYTE +
BITS_PER_BYTE + LESS_THAN_8BITS);
std::vector<GByte> in((expectedOut.size() + BITS_PER_BYTE - 1) /
BITS_PER_BYTE);
for (int i = 0; i < static_cast<int>(expectedOut.size()); ++i)
{
expectedOut[i] = (badRand() % 2) == 0 ? 0 : 255;
if (expectedOut[i])
{
in[i / BITS_PER_BYTE] = static_cast<GByte>(
in[i / BITS_PER_BYTE] |
(1 << (BITS_PER_BYTE - 1 - (i % BITS_PER_BYTE))));
}
}

std::vector<GByte> out(expectedOut.size());
GDALExpandPackedBitsToByteAt0Or255(in.data(), out.data(), out.size());

EXPECT_EQ(out, expectedOut);
}

} // namespace
91 changes: 9 additions & 82 deletions frmts/gtiff/gtiffoddbitsband.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,60 +515,6 @@ CPLErr GTiffOddBitsBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
/* IReadBlock() */
/************************************************************************/

static void ExpandPacked8ToByte1(const GByte *const CPL_RESTRICT pabySrc,
GByte *const CPL_RESTRICT pabyDest,
GPtrDiff_t nBytes)
{
for (decltype(nBytes) i = 0, j = 0; i < nBytes; i++, j += 8)
{
const GByte byVal = pabySrc[i];
pabyDest[j + 0] = (byVal >> 7) & 0x1;
pabyDest[j + 1] = (byVal >> 6) & 0x1;
pabyDest[j + 2] = (byVal >> 5) & 0x1;
pabyDest[j + 3] = (byVal >> 4) & 0x1;
pabyDest[j + 4] = (byVal >> 3) & 0x1;
pabyDest[j + 5] = (byVal >> 2) & 0x1;
pabyDest[j + 6] = (byVal >> 1) & 0x1;
pabyDest[j + 7] = (byVal >> 0) & 0x1;
}
}

#if defined(__GNUC__) || defined(_MSC_VER)
// Signedness of char implementation dependent, so be explicit.
// Assumes 2-complement integer types and sign extension of right shifting
// GCC guarantees such:
// https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation
static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
{
return static_cast<GByte>(static_cast<signed char>(byVal << (7 - nBit)) >>
7);
}
#else
// Portable way
static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
{
return (byVal & (1 << nBit)) ? 255 : 0;
}
#endif

static void ExpandPacked8ToByte255(const GByte *const CPL_RESTRICT pabySrc,
GByte *const CPL_RESTRICT pabyDest,
GPtrDiff_t nBytes)
{
for (decltype(nBytes) i = 0, j = 0; i < nBytes; i++, j += 8)
{
const GByte byVal = pabySrc[i];
pabyDest[j + 0] = ExtractBitAndConvertTo255(byVal, 7);
pabyDest[j + 1] = ExtractBitAndConvertTo255(byVal, 6);
pabyDest[j + 2] = ExtractBitAndConvertTo255(byVal, 5);
pabyDest[j + 3] = ExtractBitAndConvertTo255(byVal, 4);
pabyDest[j + 4] = ExtractBitAndConvertTo255(byVal, 3);
pabyDest[j + 5] = ExtractBitAndConvertTo255(byVal, 2);
pabyDest[j + 6] = ExtractBitAndConvertTo255(byVal, 1);
pabyDest[j + 7] = ExtractBitAndConvertTo255(byVal, 0);
}
}

CPLErr GTiffOddBitsBand::IReadBlock(int nBlockXOff, int nBlockYOff,
void *pImage)

Expand Down Expand Up @@ -608,43 +554,24 @@ CPLErr GTiffOddBitsBand::IReadBlock(int nBlockXOff, int nBlockYOff,
(m_poGDS->nBands == 1 ||
m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE))
{
/* --------------------------------------------------------------------
*/
/* Translate 1bit data to eight bit. */
/* --------------------------------------------------------------------
*/
GPtrDiff_t iDstOffset = 0;
const GByte *const CPL_RESTRICT m_pabyBlockBuf =
m_poGDS->m_pabyBlockBuf;
// Translate 1bit data to eight bit.
const GByte *CPL_RESTRICT pabySrc = m_poGDS->m_pabyBlockBuf;
GByte *CPL_RESTRICT pabyDest = static_cast<GByte *>(pImage);

for (int iLine = 0; iLine < nBlockYSize; ++iLine)
{
GPtrDiff_t iSrcOffsetByte =
static_cast<GPtrDiff_t>((nBlockXSize + 7) >> 3) * iLine;

if (!m_poGDS->m_bPromoteTo8Bits)
if (m_poGDS->m_bPromoteTo8Bits)
{
ExpandPacked8ToByte1(m_pabyBlockBuf + iSrcOffsetByte,
pabyDest + iDstOffset, nBlockXSize / 8);
GDALExpandPackedBitsToByteAt0Or255(pabySrc, pabyDest,
nBlockXSize);
}
else
{
ExpandPacked8ToByte255(m_pabyBlockBuf + iSrcOffsetByte,
pabyDest + iDstOffset, nBlockXSize / 8);
}
GPtrDiff_t iSrcOffsetBit = (iSrcOffsetByte + nBlockXSize / 8) * 8;
iDstOffset += nBlockXSize & ~0x7;
const GByte bSetVal = m_poGDS->m_bPromoteTo8Bits ? 255 : 1;
for (int iPixel = nBlockXSize & ~0x7; iPixel < nBlockXSize;
++iPixel, ++iSrcOffsetBit)
{
if (m_pabyBlockBuf[iSrcOffsetBit >> 3] &
(0x80 >> (iSrcOffsetBit & 0x7)))
static_cast<GByte *>(pImage)[iDstOffset++] = bSetVal;
else
static_cast<GByte *>(pImage)[iDstOffset++] = 0;
GDALExpandPackedBitsToByteAt0Or1(pabySrc, pabyDest,
nBlockXSize);
}
pabySrc += (nBlockXSize + 7) / 8;
pabyDest += nBlockXSize;
}
}
/* -------------------------------------------------------------------- */
Expand Down
64 changes: 6 additions & 58 deletions frmts/libertiff/libertiffdataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1161,28 +1161,6 @@ FloatingPointHorizPredictorDecode(std::vector<uint8_t> &tmpBuffer,
return true;
}

/************************************************************************/
/* ExtractBitAndConvertTo255() */
/************************************************************************/

#if defined(__GNUC__) || defined(_MSC_VER)
// Signedness of char implementation dependent, so be explicit.
// Assumes 2-complement integer types and sign extension of right shifting
// GCC guarantees such:
// https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation
static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
{
return static_cast<GByte>(static_cast<signed char>(byVal << (7 - nBit)) >>
7);
}
#else
// Portable way
static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
{
return (byVal & (1 << nBit)) ? 255 : 0;
}
#endif

/************************************************************************/
/* ReadBlock() */
/************************************************************************/
Expand Down Expand Up @@ -1577,51 +1555,21 @@ bool LIBERTIFFDataset::ReadBlock(GByte *pabyBlockData, int nBlockXOff,
if (m_image->bitsPerSample() == 1)
{
const GByte *CPL_RESTRICT pabySrc = abyDecompressedStrile.data();
const GByte val = m_bExpand1To255 ? 255 : 1;
GByte *CPL_RESTRICT pabyDst = bufferForOneBitExpansion.data();
for (int iY = 0; iY < nBlockActualYSize; ++iY)
{
int iX = 0;
if (m_bExpand1To255)
{
for (; iX + 7 < nBlockXSize;
iX += 8, ++pabySrc, pabyDst += 8)
{
const GByte srcByte = *pabySrc;
pabyDst[0] = ExtractBitAndConvertTo255(srcByte, 7);
pabyDst[1] = ExtractBitAndConvertTo255(srcByte, 6);
pabyDst[2] = ExtractBitAndConvertTo255(srcByte, 5);
pabyDst[3] = ExtractBitAndConvertTo255(srcByte, 4);
pabyDst[4] = ExtractBitAndConvertTo255(srcByte, 3);
pabyDst[5] = ExtractBitAndConvertTo255(srcByte, 2);
pabyDst[6] = ExtractBitAndConvertTo255(srcByte, 1);
pabyDst[7] = ExtractBitAndConvertTo255(srcByte, 0);
}
GDALExpandPackedBitsToByteAt0Or255(pabySrc, pabyDst,
nBlockXSize);
}
else
{
for (; iX + 7 < nBlockXSize;
iX += 8, ++pabySrc, pabyDst += 8)
{
const int srcByte = *pabySrc;
pabyDst[0] = (srcByte >> 7) & 1;
pabyDst[1] = (srcByte >> 6) & 1;
pabyDst[2] = (srcByte >> 5) & 1;
pabyDst[3] = (srcByte >> 4) & 1;
pabyDst[4] = (srcByte >> 3) & 1;
pabyDst[5] = (srcByte >> 2) & 1;
pabyDst[6] = (srcByte >> 1) & 1;
pabyDst[7] = (srcByte >> 0) & 1;
}
}
if (iX < nBlockXSize)
{
for (; iX < nBlockXSize; ++iX, ++pabyDst)
{
*pabyDst = (*pabySrc & (0x80 >> (iX % 8))) ? val : 0;
}
++pabySrc;
GDALExpandPackedBitsToByteAt0Or1(pabySrc, pabyDst,
nBlockXSize);
}
pabySrc += (nBlockXSize + 7) / 8;
pabyDst += nBlockXSize;
}

std::swap(abyDecompressedStrile, bufferForOneBitExpansion);
Expand Down
8 changes: 8 additions & 0 deletions gcore/gdal_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -4493,6 +4493,14 @@ int CPL_DLL GDALReadTabFile2(const char *pszBaseFilename,
void CPL_DLL GDALCopyRasterIOExtraArg(GDALRasterIOExtraArg *psDestArg,
GDALRasterIOExtraArg *psSrcArg);

void CPL_DLL GDALExpandPackedBitsToByteAt0Or1(
const GByte *CPL_RESTRICT pabyInput, GByte *CPL_RESTRICT pabyOutput,
size_t nInputBits);

void CPL_DLL GDALExpandPackedBitsToByteAt0Or255(
const GByte *CPL_RESTRICT pabyInput, GByte *CPL_RESTRICT pabyOutput,
size_t nInputBits);

CPL_C_END

std::unique_ptr<GDALDataset> CPL_DLL
Expand Down
Loading

0 comments on commit 4487cb9

Please sign in to comment.