25#include <freerdp/config.h>
31#include <winpr/assert.h>
32#include <winpr/cast.h>
34#include <winpr/print.h>
35#include <winpr/sysinfo.h>
36#include <winpr/bitstream.h>
37#include <winpr/intrin.h>
39#include "rfx_bitstream.h"
52#define GetMinBits(_val, _nbits) \
68static inline uint32_t UpdateParam(uint32_t* param, int32_t deltaP)
73 const uint32_t udeltaP = WINPR_ASSERTING_INT_CAST(uint32_t, -deltaP);
80 *param += WINPR_ASSERTING_INT_CAST(uint32_t, deltaP);
84 return (*param) >> LSGR;
87static BOOL g_LZCNT = FALSE;
89static INIT_ONCE rfx_rlgr_init_once = INIT_ONCE_STATIC_INIT;
91static BOOL CALLBACK rfx_rlgr_init(
PINIT_ONCE once, PVOID param, PVOID* context)
95 WINPR_UNUSED(context);
97 g_LZCNT = IsProcessorFeaturePresentEx(PF_EX_LZCNT);
101static inline UINT32 lzcnt_s(UINT32 x)
113 WINPR_ASSERT(n >= 16);
120 WINPR_ASSERT(n >= 8);
127 WINPR_ASSERT(n >= 4);
134 WINPR_ASSERT(n >= 2);
141 WINPR_ASSERT(n >= 2);
145 WINPR_ASSERT(n >= x);
152int rfx_rlgr_decode(RLGR_MODE mode,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
153 INT16* WINPR_RESTRICT pDstData, UINT32 rDstSize)
170 INT16* pOutput =
nullptr;
173 const SSIZE_T DstSize = rDstSize;
175 if (!InitOnceExecuteOnce(&rfx_rlgr_init_once, rfx_rlgr_init,
nullptr,
nullptr))
184 if ((mode != RLGR1) && (mode != RLGR3))
187 if (!pSrcData || !SrcSize)
190 if (!pDstData || !DstSize)
197 BitStream_Attach(bs, pSrcData, SrcSize);
200 while ((BitStream_GetRemainingLength(bs) > 0) && ((pOutput - pDstData) < DstSize))
210 cnt = lzcnt_s(bs->accumulator);
212 size_t nbits = BitStream_GetRemainingLength(bs);
215 cnt = WINPR_ASSERTING_INT_CAST(uint32_t, nbits);
217 vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
219 while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
221 BitStream_Shift32(bs);
223 cnt = lzcnt_s(bs->accumulator);
225 nbits = BitStream_GetRemainingLength(bs);
230 WINPR_ASSERT(cnt + vk <= UINT32_MAX);
231 vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
234 BitStream_Shift(bs, (vk % 32));
236 if (BitStream_GetRemainingLength(bs) < 1)
239 BitStream_Shift(bs, 1);
243 const UINT32 add = (1u << k);
258 if (BitStream_GetRemainingLength(bs) < k)
261 bs->mask = ((1u << k) - 1);
262 run += ((bs->accumulator >> (32 - k)) & bs->mask);
263 BitStream_Shift(bs, k);
267 if (BitStream_GetRemainingLength(bs) < 1)
270 sign = (bs->accumulator & 0x80000000) ? 1 : 0;
271 BitStream_Shift(bs, 1);
275 cnt = lzcnt_s(~(bs->accumulator));
277 nbits = BitStream_GetRemainingLength(bs);
282 vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
284 while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
286 BitStream_Shift32(bs);
288 cnt = lzcnt_s(~(bs->accumulator));
290 nbits = BitStream_GetRemainingLength(bs);
295 WINPR_ASSERT(cnt + vk <= UINT32_MAX);
296 vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
299 BitStream_Shift(bs, (vk % 32));
301 if (BitStream_GetRemainingLength(bs) < 1)
304 BitStream_Shift(bs, 1);
308 if (BitStream_GetRemainingLength(bs) < kr)
311 bs->mask = ((1u << kr) - 1);
313 code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
316 BitStream_Shift(bs, kr);
356 const INT32 code1 = code + 1;
357 if ((code1 > INT16_MAX) || (code1 < INT16_MIN))
359 WLog_ERR(RFX_TAG,
"code1=%d", code1);
364 mag = WINPR_ASSERTING_INT_CAST(int16_t, code1) * -1;
366 mag = WINPR_ASSERTING_INT_CAST(int16_t, code1);
370 offset = WINPR_ASSERTING_INT_CAST(
size_t, (pOutput)-pDstData);
373 if ((offset + size) > rDstSize)
374 size = WINPR_ASSERTING_INT_CAST(
size_t, DstSize) - offset;
378 ZeroMemory(pOutput, size *
sizeof(INT16));
382 if ((pOutput - pDstData) < DstSize)
394 cnt = lzcnt_s(~(bs->accumulator));
396 size_t nbits = BitStream_GetRemainingLength(bs);
401 vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
403 while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
405 BitStream_Shift32(bs);
407 cnt = lzcnt_s(~(bs->accumulator));
409 nbits = BitStream_GetRemainingLength(bs);
414 WINPR_ASSERT(cnt + vk <= UINT32_MAX);
415 vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
418 BitStream_Shift(bs, (vk % 32));
420 if (BitStream_GetRemainingLength(bs) < 1)
423 BitStream_Shift(bs, 1);
427 if (BitStream_GetRemainingLength(bs) < kr)
430 bs->mask = ((1u << kr) - 1);
432 code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
435 BitStream_Shift(bs, kr);
450 kr = (krp >> LSGR) & UINT32_MAX;
494 const INT32 codeShift = code >> 1;
495 const INT32 code1shift = (code + 1) >> 1;
496 if ((codeShift > INT16_MAX) || (codeShift < INT16_MIN))
498 WLog_ERR(RFX_TAG,
"codeShift=%d", codeShift);
501 if ((code1shift > INT16_MAX) || (code1shift < INT16_MIN))
503 WLog_ERR(RFX_TAG,
"code1shift=%d", code1shift);
507 mag = WINPR_ASSERTING_INT_CAST(INT16, code1shift) * -1;
509 mag = WINPR_ASSERTING_INT_CAST(INT16, codeShift);
512 if ((pOutput - pDstData) < DstSize)
518 else if (mode == RLGR3)
524 mag = WINPR_ASSERTING_INT_CAST(int16_t, code);
525 nIdx = 32 - lzcnt_s(WINPR_ASSERTING_INT_CAST(uint32_t, mag));
528 if (BitStream_GetRemainingLength(bs) < nIdx)
531 bs->mask = ((1u << nIdx) - 1);
533 val1 = ((bs->accumulator >> (32 - nIdx)) & bs->mask);
536 BitStream_Shift(bs, nIdx);
551 else if (!val1 && !val2)
563 const UINT32 val1Shift = val1 >> 1;
564 const UINT32 val11Shift = (val1 + 1) >> 1;
565 if (val1Shift > INT16_MAX)
567 WLog_ERR(RFX_TAG,
"val1Shift=%" PRIu32, val1Shift);
570 if (val11Shift > INT16_MAX)
572 WLog_ERR(RFX_TAG,
"val11Shift=%" PRIu32, val11Shift);
576 mag = WINPR_ASSERTING_INT_CAST(int16_t, val11Shift) * -1;
578 mag = WINPR_ASSERTING_INT_CAST(int16_t, val1Shift);
580 if ((pOutput - pDstData) < DstSize)
586 const UINT32 val2Shift = val2 / 2;
587 const UINT32 val21Shift = (val2 + 1) / 2;
588 if (val2Shift > INT16_MAX)
590 WLog_ERR(RFX_TAG,
"val2Shift=%" PRIu32, val2Shift);
594 if (val21Shift > INT16_MAX)
596 WLog_ERR(RFX_TAG,
"val21Shift=%" PRIu32, val21Shift);
600 mag = WINPR_ASSERTING_INT_CAST(int16_t, val21Shift) * -1;
602 mag = WINPR_ASSERTING_INT_CAST(int16_t, val2Shift);
604 if ((pOutput - pDstData) < DstSize)
606 *pOutput = WINPR_ASSERTING_INT_CAST(int16_t, mag);
613 offset = WINPR_ASSERTING_INT_CAST(
size_t, (pOutput - pDstData));
615 if (offset < rDstSize)
617 size = WINPR_ASSERTING_INT_CAST(
size_t, DstSize) - offset;
618 ZeroMemory(pOutput, size * 2);
622 offset = WINPR_ASSERTING_INT_CAST(
size_t, (pOutput - pDstData));
624 if ((DstSize < 0) || (offset != (
size_t)DstSize))
631#define GetNextInput(_n) \
646#define OutputBits(numBits, bitPattern) rfx_bitstream_put_bits(bs, bitPattern, numBits)
649static inline void OutputBit(
RFX_BITSTREAM* bs, uint32_t count, UINT8 bit)
651 UINT16 _b = ((bit) ? 0xFFFF : 0);
652 const uint32_t rem = count % 16;
653 for (uint32_t x = 0; x < count - rem; x += 16)
654 rfx_bitstream_put_bits(bs, _b, 16);
657 rfx_bitstream_put_bits(bs, _b, rem);
662static inline UINT32 Get2MagSign(INT32 input)
665 return WINPR_ASSERTING_INT_CAST(UINT32, 2 * input);
666 return WINPR_ASSERTING_INT_CAST(UINT32, -2 * input - 1);
670#define CodeGR(krp, val) rfx_rlgr_code_gr(bs, krp, val)
672static void rfx_rlgr_code_gr(
RFX_BITSTREAM* bs, uint32_t* krp, UINT32 val)
674 uint32_t kr = *krp >> LSGR;
678 const uint32_t vk = val >> kr;
679 OutputBit(bs, vk, 1);
685 OutputBits(kr, val & ((1u << kr) - 1));
691 (void)UpdateParam(krp, -2);
695 (void)UpdateParam(krp, WINPR_CXX_COMPAT_CAST(int32_t, vk));
699int rfx_rlgr_encode(RLGR_MODE mode,
const INT16* WINPR_RESTRICT data, UINT32 data_size,
700 BYTE* WINPR_RESTRICT buffer, UINT32 buffer_size)
707 rfx_bitstream_attach(bs, buffer, buffer_size);
711 uint32_t kp = 1u << LSGR;
712 uint32_t krp = 1u << LSGR;
715 while (data_size > 0)
721 uint32_t numZeros = 0;
730 while (input == 0 && data_size > 0)
738 while (numZeros >= runmax)
742 k = UpdateParam(&kp, UP_GR);
750 OutputBits(k, numZeros);
757 (UINT32)(input < 0 ? -input : input);
758 sign = (input < 0 ? 1 : 0);
760 OutputBit(bs, 1, sign);
761 CodeGR(&krp, mag ? mag - 1 : 0);
763 k = UpdateParam(&kp, -DN_GR);
777 twoMs = Get2MagSign(input);
785 k = UpdateParam(&kp, -DQ_GR);
789 k = UpdateParam(&kp, UQ_GR);
805 twoMs1 = Get2MagSign(input);
807 twoMs2 = Get2MagSign(input);
808 sum2Ms = twoMs1 + twoMs2;
810 CodeGR(&krp, sum2Ms);
813 GetMinBits(sum2Ms, nIdx);
814 OutputBits(nIdx, twoMs1);
818 if (twoMs1 && twoMs2)
820 k = UpdateParam(&kp, -2 * DQ_GR);
822 else if (!twoMs1 && !twoMs2)
824 k = UpdateParam(&kp, 2 * UQ_GR);
830 rfx_bitstream_flush(bs);
831 uint32_t processed_size = rfx_bitstream_get_processed_bytes(bs);
832 winpr_aligned_free(bs);
834 return WINPR_ASSERTING_INT_CAST(
int, processed_size);