Daemon
Daemon copied to clipboard
modifying glconfig_t breaks engine/gamecode compatibility
While working on #478 I noticed the string we use to store the list of available OpenGL extensions is smaller than the list of available OpenGL extensions itself provided by actual drivers, so I just tried to double the size this way:
diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h
index 7c4aeb672..662ae5742 100644
--- a/src/engine/renderer/tr_types.h
+++ b/src/engine/renderer/tr_types.h
@@ -335,7 +335,7 @@ struct glconfig_t
char renderer_string[ MAX_STRING_CHARS ];
char vendor_string[ MAX_STRING_CHARS ];
char version_string[ MAX_STRING_CHARS ];
- char extensions_string[ MAX_STRING_CHARS * 4 ]; // TTimo - bumping, some cards have a big extension string
+ char extensions_string[ MAX_STRING_CHARS * 8 ]; // TTimo - bumping, some cards have a big extension string
int maxTextureSize; // queried from GL
int unused;
And then when trying to load the engine from that branch with released game code I got this error:
Loaded VM module in 124 msec
Warn: Error during initialization: CGame VM: Reader: Unread bytes at end of message
Why modifying that string (and then, that struct) breaks engine/game compat? Do we need that?
This struct is used by both the game and the engine. Modifying it will in a way that changes it length, its ordering or anything else is an ABI break.
Here, by changing char extensions_string[ MAX_STRING_CHARS * 4 ];
to char extensions_string[ MAX_STRING_CHARS * 8 ];
will make this field MAX_STRING_CHARS*8
bytes long instead of MAX_STRING_CHARS*4
, and thus each instance of the struct will need a bigger memory space.
When you want to keep ABI compat in such a case, it will usually work better if every field is a pointer, as any change in the pointed object will not change the size of the struct. We don't have that unfortunately. For this specific case, we can change every string to a std::string and this specific problem will not happen again.
Keeping ABI is a complicated question though. Do we want to keep a compatible ABI between new releases of dæmon and old game? between old releases of dæmon and new games? Of course we also do want the rebuilds of both to be compatible.
I have the impression that for a game engine, we should support old releases of compiled games with a new engine. Do we need to support anything else?
Yes but do we need to share the driver list of available OpenGL extensions with the game?
We have another struct, glconfig2_t
, which seems to not be shared with the game, at least I don't see Unvanquished making use of it.
Also I don't see Unvanquished making use of extensions_string
from glconfig_t
, so maybe we can move extensions_string
from glconfig_t
to glconfig2_t
and keep a dummy one in glconfig_t
until the day we have strong reason to break the ABI.
For this specific case, we can change every string to a std::string and this specific problem will not happen again.
Not ideal, because then you have to write serialization code. I think there is very little demand from the gamelogic to know most of this stuff, so stuffing everything into glconfig2
is fine.
I have the impression that for a game engine, we should support old releases of compiled games with a new engine.
No, this is currently a non-goal. For gamelogic to run with a given engine release, it is required to build against its exact ABI. We just want gamelogics built between the last release and master to be compatible with engines built between last release and master. See Wiki - Compatibility.