Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dhewm3 on 64bit Big Endian platforms like PPC64 BE #626

Merged
merged 5 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions neo/d3xp/gamesys/Class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,18 +444,18 @@ idClass::new
#endif

void * idClass::operator new( size_t s ) {
int *p;
intptr_t *p;

s += sizeof( int );
p = (int *)Mem_Alloc( s );
s += sizeof( intptr_t );
p = (intptr_t *)Mem_Alloc( s );
*p = s;
memused += s;
numobjects++;

#ifdef ID_DEBUG_UNINITIALIZED_MEMORY
unsigned int *ptr = (unsigned int *)p;
int size = s;
assert( ( size & 3 ) == 0 );
assert( ( size & (sizeof(intptr_t) - 1) ) == 0 );
size >>= 3;
for ( int i = 1; i < size; i++ ) {
ptr[i] = 0xcdcdcdcd;
Expand All @@ -466,18 +466,18 @@ void * idClass::operator new( size_t s ) {
}

void * idClass::operator new( size_t s, int, int, char *, int ) {
int *p;
intptr_t *p;

s += sizeof( int );
p = (int *)Mem_Alloc( s );
s += sizeof( intptr_t );
p = (intptr_t *)Mem_Alloc( s );
*p = s;
memused += s;
numobjects++;

#ifdef ID_DEBUG_UNINITIALIZED_MEMORY
unsigned int *ptr = (unsigned int *)p;
int size = s;
assert( ( size & 3 ) == 0 );
assert( ( size & (sizeof(intptr_t) - 1) ) == 0 );
size >>= 3;
for ( int i = 1; i < size; i++ ) {
ptr[i] = 0xcdcdcdcd;
Expand All @@ -497,21 +497,21 @@ idClass::delete
================
*/
void idClass::operator delete( void *ptr ) {
int *p;
intptr_t *p;

if ( ptr ) {
p = ( ( int * )ptr ) - 1;
p = ( ( intptr_t * )ptr ) - 1;
memused -= *p;
numobjects--;
Mem_Free( p );
}
}

void idClass::operator delete( void *ptr, int, int, char *, int ) {
int *p;
intptr_t *p;

if ( ptr ) {
p = ( ( int * )ptr ) - 1;
p = ( ( intptr_t * )ptr ) - 1;
memused -= *p;
numobjects--;
Mem_Free( p );
Expand Down
20 changes: 18 additions & 2 deletions neo/d3xp/script/Script_Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -785,11 +785,22 @@ void idInterpreter::CallEvent( const function_t *func, int argsize ) {
switch( format[ i ] ) {
case D_EVENT_INTEGER :
var.intPtr = ( int * )&localstack[ start + pos ];
( *( int * )&data[ i ] ) = int( *var.floatPtr );
//( *( int * )&data[ i ] ) = int( *var.floatPtr );
// DG: for int/intrptr_t arguments, the callbacks from Callbacks.cpp pass
// data[i] directly, not *(int*)&data[i] or some nonsense like that
// so the integer must be assigned to the intptr_t for the value to be
// passed correctly, esp. on 64bit Big Endian machines.
data[ i ] = int( *var.floatPtr );
break;

case D_EVENT_FLOAT :
var.intPtr = ( int * )&localstack[ start + pos ];
// NOTE: floats are the only type not passed as int or pointer in intptr_t,
// but as float-data in the first 4 bytes of data[i].
// So (unlike in the other cases), here this awkward code casting &data[i]
// to another pointer type is actually necessary (same in CallSysEvent()).
// In the other cases one could also use `data[i] = (intptr_t)var.blaPtr;`
// (not doing those changes here now to minimize potential merge conflicts)
( *( float * )&data[ i ] ) = *var.floatPtr;
break;

Expand Down Expand Up @@ -915,7 +926,12 @@ void idInterpreter::CallSysEvent( const function_t *func, int argsize ) {
switch( format[ i ] ) {
case D_EVENT_INTEGER :
source.intPtr = ( int * )&localstack[ start + pos ];
*( int * )&data[ i ] = int( *source.floatPtr );
//*( int * )&data[ i ] = int( *source.floatPtr );
// DG: for int/intrptr_t arguments, the callbacks from Callbacks.cpp pass
// data[i] directly, not *(int*)&data[i] or some nonsense like that
// so the integer must be assigned to the intptr_t for the value to be
// passed correctly, esp. on 64bit Big Endian machines.
data[ i ] = int( *source.floatPtr );
break;

case D_EVENT_FLOAT :
Expand Down
21 changes: 20 additions & 1 deletion neo/d3xp/script/Script_Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,26 @@ ID_INLINE void idInterpreter::Push( intptr_t value ) {
if ( localstackUsed + sizeof( intptr_t ) > LOCALSTACK_SIZE ) {
Error( "Push: locals stack overflow\n" );
}
*( intptr_t * )&localstack[ localstackUsed ] = value;
// DG: fix for 64bit Big Endian machines
//*( intptr_t * )&localstack[ localstackUsed ] = value;
int val = value;
assert(value == val && "I really assumed that value would always fit into 32bit");
// dhewm3 used to store these values on localstack[] as intptr_t, even though
// they always seem to be int32. Unfortunately, all the code reading localstack[]
// gets the pointer to &localstack[ localstackUsed ] and then interprets that
// as int* or float* or whatever.
// So with 64bit machines it's stored as the wrong size (intptr_t is int64, int is int32),
// and on Big Endian the values are just 0 (or UINT_MAX if value < 0) - on Little Endian
// the first 4 bytes are the ones with actual data so the bug was hidden).
// To fix this, now a regular itn is stored at `&localstack[ localstackUsed ]`,
// as expected by the code using localstack[].
// TODO: once this has been tested more (and the assertion above has never triggered),
// change idInterpreter::Push() to take a regular int argument instead of intptr_t.
int *stackVar = ( int * )&localstack[ localstackUsed ];
*stackVar = val;

// even though a 32bit int is put onto the stack, increase it by sizeof(intptr_t)
// so it remains aligned to multiples of the native pointer size
localstackUsed += sizeof( intptr_t );
}

Expand Down
24 changes: 12 additions & 12 deletions neo/game/gamesys/Class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,18 +444,18 @@ idClass::new
#endif

void * idClass::operator new( size_t s ) {
int *p;
intptr_t *p;

s += sizeof( int );
p = (int *)Mem_Alloc( s );
s += sizeof( intptr_t );
p = (intptr_t *)Mem_Alloc( s );
*p = s;
memused += s;
numobjects++;

#ifdef ID_DEBUG_UNINITIALIZED_MEMORY
unsigned int *ptr = (unsigned int *)p;
int size = s;
assert( ( size & 3 ) == 0 );
assert( ( size & (sizeof(intptr_t) - 1) ) == 0 );
size >>= 3;
for ( int i = 1; i < size; i++ ) {
ptr[i] = 0xcdcdcdcd;
Expand All @@ -466,18 +466,18 @@ void * idClass::operator new( size_t s ) {
}

void * idClass::operator new( size_t s, int, int, char *, int ) {
int *p;
intptr_t *p;

s += sizeof( int );
p = (int *)Mem_Alloc( s );
s += sizeof( intptr_t );
p = (intptr_t *)Mem_Alloc( s );
*p = s;
memused += s;
numobjects++;

#ifdef ID_DEBUG_UNINITIALIZED_MEMORY
unsigned int *ptr = (unsigned int *)p;
int size = s;
assert( ( size & 3 ) == 0 );
assert( ( size & (sizeof(intptr_t) - 1) ) == 0 );
size >>= 3;
for ( int i = 1; i < size; i++ ) {
ptr[i] = 0xcdcdcdcd;
Expand All @@ -497,21 +497,21 @@ idClass::delete
================
*/
void idClass::operator delete( void *ptr ) {
int *p;
intptr_t *p;

if ( ptr ) {
p = ( ( int * )ptr ) - 1;
p = ( ( intptr_t * )ptr ) - 1;
memused -= *p;
numobjects--;
Mem_Free( p );
}
}

void idClass::operator delete( void *ptr, int, int, char *, int ) {
int *p;
intptr_t *p;

if ( ptr ) {
p = ( ( int * )ptr ) - 1;
p = ( ( intptr_t * )ptr ) - 1;
memused -= *p;
numobjects--;
Mem_Free( p );
Expand Down
20 changes: 18 additions & 2 deletions neo/game/script/Script_Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -785,11 +785,22 @@ void idInterpreter::CallEvent( const function_t *func, int argsize ) {
switch( format[ i ] ) {
case D_EVENT_INTEGER :
var.intPtr = ( int * )&localstack[ start + pos ];
( *( int * )&data[ i ] ) = int( *var.floatPtr );
//( *( int * )&data[ i ] ) = int( *var.floatPtr );
// DG: for int/intrptr_t arguments, the callbacks from Callbacks.cpp pass
// data[i] directly, not *(int*)&data[i] or some nonsense like that
// so the integer must be assigned to the intptr_t for the value to be
// passed correctly, esp. on 64bit Big Endian machines.
data[ i ] = int( *var.floatPtr );
break;

case D_EVENT_FLOAT :
var.intPtr = ( int * )&localstack[ start + pos ];
// NOTE: floats are the only type not passed as int or pointer in intptr_t,
// but as float-data in the first 4 bytes of data[i].
// So (unlike in the other cases), here this awkward code casting &data[i]
// to another pointer type is actually necessary (same in CallSysEvent()).
// In the other cases one could also use `data[i] = (intptr_t)var.blaPtr;`
// (not doing those changes here now to minimize potential merge conflicts)
( *( float * )&data[ i ] ) = *var.floatPtr;
break;

Expand Down Expand Up @@ -915,7 +926,12 @@ void idInterpreter::CallSysEvent( const function_t *func, int argsize ) {
switch( format[ i ] ) {
case D_EVENT_INTEGER :
source.intPtr = ( int * )&localstack[ start + pos ];
*( int * )&data[ i ] = int( *source.floatPtr );
//*( int * )&data[ i ] = int( *source.floatPtr );
// DG: for int/intrptr_t arguments, the callbacks from Callbacks.cpp pass
// data[i] directly, not *(int*)&data[i] or some nonsense like that
// so the integer must be assigned to the intptr_t for the value to be
// passed correctly, esp. on 64bit Big Endian machines.
data[ i ] = int( *source.floatPtr );
break;

case D_EVENT_FLOAT :
Expand Down
21 changes: 20 additions & 1 deletion neo/game/script/Script_Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,26 @@ ID_INLINE void idInterpreter::Push( intptr_t value ) {
if ( localstackUsed + sizeof( intptr_t ) > LOCALSTACK_SIZE ) {
Error( "Push: locals stack overflow\n" );
}
*( intptr_t * )&localstack[ localstackUsed ] = value;
// DG: fix for 64bit Big Endian machines
//*( intptr_t * )&localstack[ localstackUsed ] = value;
int val = value;
assert(value == val && "I really assumed that value would always fit into 32bit");
// dhewm3 used to store these values on localstack[] as intptr_t, even though
// they always seem to be int32. Unfortunately, all the code reading localstack[]
// gets the pointer to &localstack[ localstackUsed ] and then interprets that
// as int* or float* or whatever.
// So with 64bit machines it's stored as the wrong size (intptr_t is int64, int is int32),
// and on Big Endian the values are just 0 (or UINT_MAX if value < 0) - on Little Endian
// the first 4 bytes are the ones with actual data so the bug was hidden).
// To fix this, now a regular itn is stored at `&localstack[ localstackUsed ]`,
// as expected by the code using localstack[].
// TODO: once this has been tested more (and the assertion above has never triggered),
// change idInterpreter::Push() to take a regular int argument instead of intptr_t.
int *stackVar = ( int * )&localstack[ localstackUsed ];
*stackVar = val;

// even though a 32bit int is put onto the stack, increase it by sizeof(intptr_t)
// so it remains aligned to multiples of the native pointer size
localstackUsed += sizeof( intptr_t );
}

Expand Down
10 changes: 10 additions & 0 deletions neo/libs/imgui/imconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,13 @@ namespace ImGui
void MyFunction(const char* name, MyMatrix44* mtx);
}
*/

// DG: on Big Endian systems the order of color channels in an uint32 color is inverted.
// this seems to be the official way to support Big Endian platforms in ImGUI:
#if D3_IS_BIG_ENDIAN
#define IM_COL32_R_SHIFT 24
#define IM_COL32_G_SHIFT 16
#define IM_COL32_B_SHIFT 8
#define IM_COL32_A_SHIFT 0
#define IM_COL32_A_MASK 0x000000FF
#endif
Loading