diff --git a/rehlds/engine/common.cpp b/rehlds/engine/common.cpp index 66b1ad0..94b7c3a 100644 --- a/rehlds/engine/common.cpp +++ b/rehlds/engine/common.cpp @@ -28,10 +28,6 @@ #include "precompiled.h" - - - - char serverinfo[MAX_INFO_STRING]; char gpszVersionString[32]; @@ -459,9 +455,29 @@ void MSG_WriteUsercmd(sizebuf_t *buf, usercmd_t *to, usercmd_t *from) typedef struct bf_write_s { + + //For enhanced and safe bits writing functions +#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) + +#pragma pack(push, 1) + union { + uint64 u64; + uint32 u32[2]; + uint8 u8[8]; + } pendingData; + uint64 sse_highbits; +#pragma pack(pop) + + int nCurOutputBit; + sizebuf_t *pbuf; + +#else //defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) + int nCurOutputBit; unsigned char *pOutByte; sizebuf_t *pbuf; + +#endif //defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) } bf_write_t; typedef struct bf_read_s @@ -476,7 +492,7 @@ typedef struct bf_read_s // Bit field reading/writing storage. bf_read_t bfread; -bf_write_t bfwrite; +ALIGN16 bf_write_t bfwrite; void COM_BitOpsInit(void) @@ -485,6 +501,68 @@ void COM_BitOpsInit(void) Q_memset(&bfread, 0, sizeof(bf_read_t)); } +//Enhanced and safe bits writing functions +#if defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) + +void MSG_WBits_MaybeFlush() { + if (bfwrite.nCurOutputBit < 32) + return; + + uint32* pDest = (uint32*)SZ_GetSpace(bfwrite.pbuf, 4); + if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED)) + *pDest = bfwrite.pendingData.u32[0]; + + bfwrite.pendingData.u32[0] = bfwrite.pendingData.u32[1]; + bfwrite.pendingData.u32[1] = 0; + bfwrite.nCurOutputBit -= 32; +} + +void MSG_WriteBits(uint32 data, int numbits) +{ + uint32 maxval = _mm_cvtsi128_si32(_mm_slli_epi64(_mm_cvtsi32_si128(1), numbits)) - 1; //maxval = (1 << numbits) - 1 + if (data > maxval) + data = maxval; + + MSG_WBits_MaybeFlush(); + + __m128i pending = _mm_load_si128((__m128i*) &bfwrite.pendingData.u64); + + __m128i mmdata = _mm_slli_epi64(_mm_cvtsi32_si128(data), bfwrite.nCurOutputBit); //mmdata = data << bfwrite.nCurOutputBit + pending = _mm_or_si128(pending, mmdata); + + _mm_store_si128((__m128i*) &bfwrite.pendingData.u64, pending); + bfwrite.nCurOutputBit += numbits; +} + +void MSG_WriteOneBit(int nValue) { + MSG_WriteBits(nValue, 1); +} + +void MSG_StartBitWriting(sizebuf_t *buf) +{ + bfwrite.nCurOutputBit = 0; + bfwrite.pbuf = buf; + bfwrite.pendingData.u64 = 0; +} + +void MSG_EndBitWriting(sizebuf_t *buf) +{ + int bytesNeed = bfwrite.nCurOutputBit / 8; + if ((bfwrite.nCurOutputBit % 8) || bytesNeed == 0) { + bytesNeed++; + } + + uint8* pData = (uint8*)SZ_GetSpace(bfwrite.pbuf, bytesNeed); + if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED)) { + for (int i = 0; i < bytesNeed; i++) { + pData[i] = bfwrite.pendingData.u8[i]; + } + } + +} + +#else //defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) + void MSG_WriteOneBit(int nValue) { if (bfwrite.nCurOutputBit >= 8) @@ -582,6 +660,8 @@ void MSG_WriteBits(uint32 data, int numbits) } } +#endif //defined(REHLDS_OPT_PEDANTIC) || defined(REHLDS_FIXES) + void MSG_WriteSBits(int data, int numbits) { int idata = data; diff --git a/rehlds/unittests/common_tests.cpp b/rehlds/unittests/common_tests.cpp index 9a998b6..9d86158 100644 --- a/rehlds/unittests/common_tests.cpp +++ b/rehlds/unittests/common_tests.cpp @@ -1,17 +1,22 @@ #include "precompiled.h" #include "cppunitlite/TestHarness.h" -TEST(BitsWritingReading, MSG, 5000) +TEST(BitsWritingReading, MSG, 1000) { - // TODO: Move to apropriate Init function - int size = 4 * 1024 * 1024; - Memory_Init(new char[size], size); - SZ_Alloc("net_message", &net_message, 1024); + byte localBuf[1024]; sizebuf_t *buf = &net_message; + buf->buffername = "net_message"; + buf->data = localBuf; + buf->maxsize = sizeof(localBuf); + buf->cursize = 0; + buf->flags = SIZEBUF_CHECK_OVERFLOW; uint32 ff1 = ((uint32)1 << 31) - 1; uint32 ff2 = ((uint32)1 << 9) - 1; + uint32 ff3 = 0xFFFFFFFF; + + uint32 t1, t2, t3; SZ_Clear(buf); @@ -23,8 +28,8 @@ TEST(BitsWritingReading, MSG, 5000) MSG_BeginReading(); MSG_StartBitReading(buf); - uint32 t1 = MSG_ReadBits(31); - uint32 t2 = MSG_ReadBits(9); + t1 = MSG_ReadBits(31); + t2 = MSG_ReadBits(9); MSG_EndBitReading(buf); UINT32_EQUALS("31/9 Read failed (31)", ff1, t1); @@ -49,6 +54,28 @@ TEST(BitsWritingReading, MSG, 5000) UINT32_EQUALS("9/31 Read failed (31)", ff2, t2); + + SZ_Clear(buf); + + MSG_StartBitWriting(buf); + MSG_WriteBits(ff2, 9); + MSG_WriteBits(ff3, 32); + MSG_WriteBits(ff1, 31); + MSG_EndBitWriting(buf); + + MSG_BeginReading(); + + MSG_StartBitReading(buf); + t2 = MSG_ReadBits(9); + t3 = MSG_ReadBits(32); + t1 = MSG_ReadBits(31); + MSG_EndBitReading(buf); + + UINT32_EQUALS("9/32/31 Read failed (9)", ff1, t1); + UINT32_EQUALS("9/32/31 Read failed (32)", ff3, t3); + UINT32_EQUALS("9/32/31 Read failed (31)", ff2, t2); + + uint32 a2, a1 = 5; uint32 b2, b1 = 0xEFEF; uint32 c2, c1 = 0x7AAEAEAE; @@ -86,4 +113,37 @@ TEST(BitsWritingReading, MSG, 5000) UINT32_EQUALS("7/16/31 Read failed", a1, a2); UINT32_EQUALS("7/16/31 Read failed", b1, b2); UINT32_EQUALS("7/16/31 Read failed", c1, c2); + + + SZ_Clear(buf); + + MSG_StartBitWriting(buf); + MSG_WriteBits(a1, 7); + MSG_WriteBits(b1, 16); + MSG_WriteBits(c1, 31); + MSG_WriteBits(a1, 7); + MSG_WriteBits(b1, 16); + MSG_WriteBits(c1, 31); + + MSG_EndBitWriting(buf); + + MSG_BeginReading(); + + MSG_StartBitReading(buf); + a2 = MSG_ReadBits(7); + b2 = MSG_ReadBits(16); + c2 = MSG_ReadBits(31); + UINT32_EQUALS("7/16/31 Read failed", a1, a2); + UINT32_EQUALS("7/16/31 Read failed", b1, b2); + UINT32_EQUALS("7/16/31 Read failed", c1, c2); + + a2 = MSG_ReadBits(7); + b2 = MSG_ReadBits(16); + c2 = MSG_ReadBits(31); + UINT32_EQUALS("7/16/31 Read failed", a1, a2); + UINT32_EQUALS("7/16/31 Read failed", b1, b2); + UINT32_EQUALS("7/16/31 Read failed", c1, c2); + + MSG_EndBitReading(buf); + }