Skip to content

Commit

Permalink
engine: common: simplify bit buffer operations
Browse files Browse the repository at this point in the history
Yields a small performance boost
  • Loading branch information
a1batross committed Apr 8, 2024
1 parent 2f2780c commit 1677835
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 121 deletions.
2 changes: 1 addition & 1 deletion engine/common/masterlist.c
Expand Up @@ -118,7 +118,7 @@ static void NET_AnnounceToMaster( master_t *m )
MSG_WriteBytes( &msg, "q\xFF", 2 );
MSG_WriteDword( &msg, m->heartbeat_challenge );

NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetBuf( &msg ), m->adr );
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetData( &msg ), m->adr );

if( sv_verbose_heartbeats.value )
{
Expand Down
91 changes: 11 additions & 80 deletions engine/common/net_buffer.c
Expand Up @@ -109,85 +109,6 @@ void MSG_InitMasks( void )
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
}

void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits )
{
MSG_StartWriting( sb, pData, nBytes, 0, nMaxBits );

sb->pDebugName = pDebugName;
}

void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
{
// make sure it's dword aligned and padded.
Assert(((uint32_t)pData & 3 ) == 0 );

sb->pDebugName = "Unnamed";
sb->pData = (byte *)pData;

if( nBits == -1 )
{
sb->nDataBits = nBytes << 3;
}
else
{
Assert( nBits <= nBytes * 8 );
sb->nDataBits = nBits;
}

sb->iCurBit = iStartBit;
sb->bOverflow = false;
}

/*
=======================
MSG_Clear
for clearing overflowed buffer
=======================
*/
void MSG_Clear( sizebuf_t *sb )
{
sb->iCurBit = 0;
sb->bOverflow = false;
}

static qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
{
if( sb->iCurBit + nBits > sb->nDataBits )
sb->bOverflow = true;
return sb->bOverflow;
}

qboolean MSG_CheckOverflow( sizebuf_t *sb )
{
return MSG_Overflow( sb, 0 );
}

int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence )
{
// compute the file offset
switch( whence )
{
case SEEK_CUR:
bitPos += sb->iCurBit;
break;
case SEEK_SET:
break;
case SEEK_END:
bitPos += sb->nDataBits;
break;
default:
return -1;
}

if( bitPos < 0 || bitPos > sb->nDataBits )
return -1;

sb->iCurBit = bitPos;

return 0;
}

void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
{
if( !MSG_Overflow( sb, 1 ))
Expand Down Expand Up @@ -669,7 +590,7 @@ qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
return MSG_ReadBits( sb, pOut, nBytes << 3 );
}

char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
{
static char string[4096];
int l = 0, c;
Expand All @@ -695,6 +616,16 @@ char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
return string;
}

char *MSG_ReadString( sizebuf_t *sb )
{
return MSG_ReadStringExt( sb, false );
}

char *MSG_ReadStringLine( sizebuf_t *sb )
{
return MSG_ReadStringExt( sb, true );
}

void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove )
{
int i, endbit = startbit + bitstoremove;
Expand Down
161 changes: 124 additions & 37 deletions engine/common/net_buffer.h
Expand Up @@ -30,39 +30,128 @@ GNU General Public License for more details.
// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4
#define PAD_NUMBER( num, boundary ) ((( num ) + (( boundary ) - 1 )) / ( boundary )) * ( boundary )

_inline int BitByte( int bits )
static inline int BitByte( int bits )
{
return PAD_NUMBER( bits, 8 ) >> 3;
}

struct sizebuf_s
{
qboolean bOverflow; // overflow reading or writing
const char *pDebugName; // buffer name (pointer to const name)

byte *pData;
int iCurBit;
int nDataBits;
byte *pData;
qboolean bOverflow; // overflow reading or writing
int iCurBit;
int nDataBits;
const char *pDebugName; // buffer name (pointer to const name)
};

#define MSG_StartReading MSG_StartWriting
#define MSG_GetNumBytesRead MSG_GetNumBytesWritten
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord
#define MSG_ReadString( sb ) MSG_ReadStringExt( sb, false )
#define MSG_ReadStringLine( sb ) MSG_ReadStringExt( sb, true )
#define MSG_ReadAngle( sb ) (float)(MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
#define MSG_StartReading MSG_StartWriting
#define MSG_GetNumBytesRead MSG_GetNumBytesWritten
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord
#define MSG_ReadAngle( sb ) (float)( MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
#define MSG_CheckOverflow( sb ) MSG_Overflow( sb, 0 )

// common functions
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits );
void MSG_InitMasks( void ); // called once at startup engine
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence );
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
_inline int MSG_TellBit( sizebuf_t *sb ) { return sb->iCurBit; }
_inline const char *MSG_GetName( sizebuf_t *sb ) { return sb->pDebugName; }
qboolean MSG_CheckOverflow( sizebuf_t *sb );
static inline void MSG_Clear( sizebuf_t *sb )
{
sb->bOverflow = false;
sb->iCurBit = 0;
}

static inline void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nBits )
{
sb->pData = pData;
MSG_Clear( sb );

if( nBits < 0 )
sb->nDataBits = nBytes << 3;
else
sb->nDataBits = nBits;

sb->pDebugName = pDebugName;
}

static inline void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
{
MSG_InitExt( sb, "Unnamed", pData, nBytes, nBits );
sb->iCurBit = iStartBit;
}

static inline int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence )
{
// compute the file offset
switch( whence )
{
case SEEK_CUR:
bitPos += sb->iCurBit;
break;
case SEEK_SET:
break;
case SEEK_END:
bitPos += sb->nDataBits;
break;
default:
return -1;
}

if( unlikely( bitPos < 0 || bitPos > sb->nDataBits ))
return -1;

sb->iCurBit = bitPos;

return 0;
}

static inline int MSG_TellBit( sizebuf_t *sb )
{
return sb->iCurBit;
}

static inline const char *MSG_GetName( sizebuf_t *sb )
{
return sb->pDebugName;
}

static inline int MSG_GetNumBytesWritten( sizebuf_t *sb )
{
return BitByte( sb->iCurBit );
}

static inline int MSG_GetRealBytesWritten( sizebuf_t *sb )
{
return sb->iCurBit >> 3; // unpadded
}
static inline int MSG_GetNumBitsWritten( sizebuf_t *sb )
{
return sb->iCurBit;
}

static inline int MSG_GetMaxBits( sizebuf_t *sb )
{
return sb->nDataBits;
}

static inline int MSG_GetMaxBytes( sizebuf_t *sb )
{
return sb->nDataBits >> 3;
}

static inline int MSG_GetNumBitsLeft( sizebuf_t *sb )
{
return sb->nDataBits - sb->iCurBit;
}

static inline int MSG_GetNumBytesLeft( sizebuf_t *sb )
{
return MSG_GetNumBitsLeft( sb ) >> 3;
}

static inline byte *MSG_GetData( sizebuf_t *sb )
{
return sb->pData;
}

#if XASH_BIG_ENDIAN
#define MSG_BigShort( x ) ( x )
Expand All @@ -73,9 +162,15 @@ static inline uint16_t MSG_BigShort( const uint16_t x )
}
#endif

// init writing
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits );
void MSG_Clear( sizebuf_t *sb );
static inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
{
if( sb->iCurBit + nBits > sb->nDataBits )
sb->bOverflow = true;
return sb->bOverflow;
}

void MSG_InitMasks( void ); // called once at startup engine
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );

// Bit-write functions
void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
Expand All @@ -99,20 +194,11 @@ void MSG_WriteCoord( sizebuf_t *sb, float val );
void MSG_WriteFloat( sizebuf_t *sb, float val );
void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
void MSG_WriteVec3Angles( sizebuf_t *sb, const float *fa );
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes ); // same as MSG_WriteData
qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr ); // returns false if it overflows the buffer.
qboolean MSG_WriteStringf( sizebuf_t *sb, const char *format, ... ) _format( 2 );
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes );

// helper functions
_inline int MSG_GetNumBytesWritten( sizebuf_t *sb ) { return BitByte( sb->iCurBit ); }
_inline int MSG_GetRealBytesWritten( sizebuf_t *sb ) { return sb->iCurBit >> 3; } // unpadded
_inline int MSG_GetNumBitsWritten( sizebuf_t *sb ) { return sb->iCurBit; }
_inline int MSG_GetMaxBits( sizebuf_t *sb ) { return sb->nDataBits; }
_inline int MSG_GetMaxBytes( sizebuf_t *sb ) { return sb->nDataBits >> 3; }
_inline int MSG_GetNumBitsLeft( sizebuf_t *sb ) { return sb->nDataBits - sb->iCurBit; }
_inline int MSG_GetNumBytesLeft( sizebuf_t *sb ) { return MSG_GetNumBitsLeft( sb ) >> 3; }
_inline byte *MSG_GetData( sizebuf_t *sb ) { return sb->pData; }
_inline byte *MSG_GetBuf( sizebuf_t *sb ) { return sb->pData; } // just an alias

// Bit-read functions
int MSG_ReadOneBit( sizebuf_t *sb );
Expand All @@ -136,7 +222,8 @@ float MSG_ReadCoord( sizebuf_t *sb );
float MSG_ReadFloat( sizebuf_t *sb );
void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
void MSG_ReadVec3Angles( sizebuf_t *sb, vec3_t fa );
char *MSG_ReadString( sizebuf_t *sb );
char *MSG_ReadStringLine( sizebuf_t *sb );
qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes );
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine );

#endif//NET_BUFFER_H
6 changes: 3 additions & 3 deletions engine/server/sv_frame.c
Expand Up @@ -811,17 +811,17 @@ static void SV_UpdateToReliableMessages( void )
continue; // reliables go to all connected or spawned

if( MSG_GetNumBytesWritten( &sv.reliable_datagram ) < MSG_GetNumBytesLeft( &cl->netchan.message ))
MSG_WriteBits( &cl->netchan.message, MSG_GetBuf( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram ));
MSG_WriteBits( &cl->netchan.message, MSG_GetData( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram ));
else Netchan_CreateFragments( &cl->netchan, &sv.reliable_datagram );

if( MSG_GetNumBytesWritten( &sv.datagram ) < MSG_GetNumBytesLeft( &cl->datagram ))
MSG_WriteBits( &cl->datagram, MSG_GetBuf( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram ));
MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram ));
else Con_DPrintf( S_WARN "Ignoring unreliable datagram for %s, would overflow\n", cl->name );

if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
{
if( MSG_GetNumBytesWritten( &sv.spec_datagram ) < MSG_GetNumBytesLeft( &cl->datagram ))
MSG_WriteBits( &cl->datagram, MSG_GetBuf( &sv.spec_datagram ), MSG_GetNumBitsWritten( &sv.spec_datagram ));
MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.spec_datagram ), MSG_GetNumBitsWritten( &sv.spec_datagram ));
else Con_DPrintf( S_WARN "Ignoring spectator datagram for %s, would overflow\n", cl->name );
}
}
Expand Down

0 comments on commit 1677835

Please sign in to comment.