This document contains low-level implementation details of GLERI, intended for people wishing to modify the library or to enable interoperation with other services. It is not useful if you only want to write applications using GLERI.

GLERI communicates over a socket connection, UNIX or TCP, using the protocols described here. These protocols are implemented on top of a more or less generic message bus system. The message bus itself uses the COM protocol, while the GLERI functionality is implemented by the RGL and RGLR protocol pair. Also described here is the compiled drawlist format that forms the RGL.Draw message.

The Message Bus

The messaging protocol is implemented in gleri/cmd.h. Messages are sent to a remote object through a local proxy object. For example, the RGL protocol is implemented in gleris by the CGleris and CGLWindow classes, CGleris managing the open windows and CGLWindow representing each window. These objects are created and accessed through the PRGL proxy object, by convention having a name prefixed with P. Each connection is strictly one-way, and instead of replies a reply interface is defined. In gleris, the RGL interface is represented by PRGL->CGLWindow, and the reply interface is represented by the PRGLR->CWindow link. Note the ending of the reply proxy name with an R - this is required by the code to differentiate between the outgoing and reply protocols. Server proxies can create remote objects, while reply proxies can only contact existing objects.

Proxy objects are designed to permit using remote objects in the same manner as using a local object. Member functions of a proxy objects serialize arguments into a message and place it into an outgoing buffer implemented by CCmdBuf class, from which all proxy objects must be derived. At some convenient point, the contents of the message buffer have to be written to the socket. In GLERI, this is done by the app object which owns the socket.

Remote objects are addressed by a string name, such as "RGL". Object versions, if present, should be made part of the name, like "RGL2", permitting an executable to support multiple object versions simultaneously. Each created object has an instance id, encoded in each message. Method names are also strings, consisting of the name and argument signature concatenated with a zero. For example, "LoadData\0uqquuay". The signature contains letters designating the type of each argument. The meaning of the letters has been copied from the specification for DBus, which uses a similar system for encoding arguments. Unless otherwise specified, all arguments are encoded directly, as in *(uint32_t*)p = arg; integer byte order is always little-endian, here and elsewhere in the protocol. Values must be aligned to the same alignment requrement as in memory. Typically that is the size of the type.

yuint8_t
quint16_t
nint16_t
uuint32_t
iint32_t
xuint64_t
tint64_t
ffloat
ddouble
bbool. Encoded as uint8_t.
a Array. The next letter denotes array type. Encoded with uint32_t number of elements followed by the serialized array elements, padded to 4-byte alignment. If the elements require alignment greater than 4, the first element is aligned to the appropriate grain.
s String. Encoding same as array, with size equal to the length of the string including the zero terminator.
hFile descriptor. Only valid for messages sent over a UNIX socket. No dummy data is sent with the SCM_RIGHTS call, use the message itself as msg_iov data required for it.
()Delimit compound types. Useful after a

The message consists of header and body. The header, the body, and the end of the message must be 8-byte aligned. The header is:

struct {
    uint32_t    sz;
    uint16_t    iid;
    uint8_t     fdoffset;
    uint8_t     hsz;
    char	objname[];
    char	method[];
    char	signature[];
}

sz is the size of the message body padded to 8 byte alignment. hsz is the size of the header padded to 8 byte alignment. fdoffset is the offset of the passed file descriptor in the body; if no file descriptor is passed, this should be 0xff. iid is the instance id of the destination object. Generated by the caller. iid must be unique for the connection, not just for each object type. objname, method, and signature encode the message destination as described above. All three are zero-terminated strings, concatenated together and directly following hsz.

The typical implementation defines a proxy object and a server object. The proxy object defines all methods, marshalling the arguments into the message buffer, and the server parser template. Putting the code for outgoing marshalling and the result parser in one place is intended to simplify the notoriously unpleasant debugging of serialization errors. It also allows multiple server object implementations and attaching the remoting capability to objects not written for it, such as ones in third party libraries.

COM

The COM interface contains functionality internal to the message bus protocol. There are two methods currently defined:

Export (const char* el), signature "s".
Must the first message sent by both sides after establishing a connection. The argument is a comma-delimited list of supported protocols. Reply protocols are included.
Error (const char* msg), signature "s".
Sent by the server object when it encounters an error. In the GLERI implementation this is done automatically by the top level parser in CCmdBuf by catching and forwarding exceptions. CGLApp will convert these into thrown exceptions in the client.

RGL

This is the server GLERI protocol, defined in gleri/rglp.h and implemented by two gleris objects CGleris and CGLWindow. Its interface provides functionality for creating and manipulating windows and OpenGL resources. For several technical reasons there is an enforced split between creating resources, such as vertex buffers and textures, and rendering them. Resources can be loaded from raw data, from files, or from a datapak, which is a gzip compressed cpio archive. Resource types are defined by the PRGL::EResource enum in gleri/rglp.h, corresponding to the OpenGL objects named by the like-named GL_ constants.

Resource ids are generated by the client object and must be unique to the connection because all resources are automatically shared between all windows created by a connection. There are also resources shared globally among all windows owned by one instance of gleris. These resources have ids less than G::default_ResourceMaxId, which are reserved for this purpose. Default resources are defined by the G::DefaultResource enum in gleri/gldefs.h.

Once a resource is created, the server object will send a resource info back to the client, contents dependent on the resource type. Textures will send a G::Texture::Header, containing texture dimensions and format. Fonts send a G::Font::Info, containing font metrics for measuring text.

After resources are created, they can be drawn on the screen or an offscreen framebuffer by using the Draw call. See section below on the format of the drawlist. The Draw call serves as an atomic frame boundary, containing everything needed to render one complete frame. The drawlist can be reused multiple times by the server object to redraw the window, which is one of the reasons for the resource creation vs drawing separation.

Auth (SArgv argv, const char* hostname, pid_t pid, unsigned screen, SDataBlock authdata, signature "aysuuay".
A connection-wide authentication call to be used once at startup, right after the COM::Export message. Contains information about the client process, used to set various X window properties for the window manager, and the X11 authentication token, used to verify that the client has access to the display.
Open (G::WinInfo winfo, const char* title), signature "(nnqqqyyyyyy)s".
Opens a window with requested parameters. Note that this is always a top-level window, X-parented to root - subwindows are not supported because they do not play well with OpenGL. The parent window id in winfo is an iid of another window created in the same connection, and is used to set an X property for the window manager. The G::WinInfo structure is defined in gleri/gldefs.h.
Close (void), signature "".
Closes the calling window.
Draw (goid_t fb, SDataBlock dl, signature "uay".
Renders drawlist dl to framebuffer fb. The format of the drawlist is documented in the next section. If rendering to the screen (G::default_Framebuffer), buffer swap is initiated at the end.
Event (CEvent e), signature "(unnuu)".
Sends a client event. The CEvent structure is defined in gleri/event.h. Currently this is only used to implement the _NET_WM_PING protocol.
LoadData (goid_t id, EResource dtype, uint16_t hint, SDataBlock data), signature "uqquuay".
Creates a resource of dtype from data with resource-specific hint. The id is generated by the client, and must be a new id. Load calls create a new OpenGL object and thus require a new id. The data will be sent in the message body. The two uint32_t fields before the data block are fragment infos, a sending mode not currently implemented.
LoadFile (goid_t id, EResource dtype, uint16_t hint, int fd), signature "uqqh".
Creates a resource of dtype from the contents of open file fd. This call is only valid for UNIX sockets where the file descriptor can be directly passed to the server. PRGL will determine if this capability is available and will otherwise fallback to LoadData, reading the file into the message body.
LoadPakFile (goid_t id, EResource dtype, uint16_t hint, goid_t datapak, const char* file), signature "uqqus".
Creates a resource of dtype from a file in datapak.
FreeResource (goid_t id, EResource dtype), signature "uq".
Frees resource id of dtype.
BufferSubData (goid_t id, uint32_t offset, SDataBlock data), signature "uuay".
Rewrites part of a buffer resource id at offset with data. id must have been created by an earler call to one of the Load functions above.
TexParameter (G::TextureType t, G::Texture::Parameter p, int v), signature "qqi".
Sets a texture parameter p for texture type t to v. See gleri/gldefs.h for the list of available parameters. Typically this is used to enable texture smoothing. The parameter set will be used for subsequently loaded textures.

RGLR

The reply side of the RGL protocol is used by the server object to send back events and other information to the window object in the client. In GLERI the proxy and parser are implemented by PRGLR in gleri/rglrp.h and CWindow in gleri/window.h. As mentioned above, CWindow always represents a toplevel window. Subwindows are implemented strictly on the client with CWidget objects.

Restate (G::WinInfo info), signature "(nnqqyyyy)".
Contains the current window info structure, sent whenever it changes, such as after creation or resizing.
Expose (void), signature "".
A request to redraw the window.
Event (CEvent e), signature "(unnuu)".
UI event. See gleri/event.h for the CEvent structure and various constants for values therein.
SaveFB (goid_t fbid, uint32_t reserved, int fd), signature "uuh".
A reply to the SaveFramebuffer command in a drawlist, contains the id of the saved framebuffer and the descriptor of the file with the saved data. This message is used only on UNIX sockets; use the SaveFBData call to send the framebuffer data in the message body.
SaveFBData (goid_t fbid, const char* filename, uint32_t totalsz, uint32_t offset, SDataBlock data), signature "usuuay".
Same as the SaveFB message, only with the framebuffer data embedded in the message body. The destination filename requested by the SaveFramebuffer command is included so the client can create that file. The totalsz and offset values are for the currently unimplemented fragment mode.
ResInfo (goid_t resid, EResource type, uint16_t reserved, SDataBlock data, signature "uqqay".
Sent after creating the resource resid of type. data contains the serialized resource-specific information structure. Texture resources send a G::Texture::Header. Font resources send G::Font::Info.

Drawlist Format

The drawlist sent in the RGL::Draw is composed from a list of draw commands written using the PDraw object, defined in gleri/drawp.h. Each command begins with a struct header { ECmd cmd; uint16_t sz; }, cmd being the command id from the PDraw::ECmd enum, and sz being the size of the arguments following the header. Each command must be a multiple of 4 bytes in size.

Most of the commands directly correspond to the OpenGL function of the same name. The default environment is set up for 2D drawing, so if that's all you're doing, you should not need to deal with writing shaders. This by no means implies that GLERI only allows 2D output, but if you want to do 3D, you'll need to write your own shaders, build the transform matrix, and do all the other things just as described in OpenGL tutorials you'll find elsewhere. GLERI uses core profiles, so look at GL 3.3 tutorials.

There are two default shaders available. G::default_FlatShader will fill primitives with a solid color, set by the Color command. The primitives are defined by x,y int16_t pairs, ordered counterclockwise. Right hand coordinate system is in use. The second shader is G::default_GradientShader, which takes an additional uint32_t color parameter per vertex, and produces smoothly shaded primitives.

See gleri/gldefs.h for the definitions of the G:: constants.

Here are the commands with their protocol names and parameters:

Clear (uint32_t color)
Clear screen with color. Colors are defined with the RGB(r,g,b) helper functions. Stored colors are in RGBA little-endian format.
Viewport (int16_t x, int16_t y, uint16_t w, uint16_t h)
Sets viewport for subsequent draw commands. All zeroes means reset to full window.
Offset (int16_t x, int16_t y)
Adds an offset to the default transform matrix.
Scale (float x, float y)
Adds a scaling factor to the default transform matrix.
Enable (G::Feature f, uint16_t onoff)
Enable (onoff=1) or disable (onoff=0) feature. See gleri/gldefs.h
Color (uint32_t c)
Set color parameter to the default shader
Text (int16_t x, int16_t y, const char* s)
Draw text at specified coordinates in currently active font. See BindFont
Image (int16_t x, int16_t y, goid_t s)
Draws full texture s at x,y
Sprite (int16_t x, int16_t y, goid_t s, int16_t sx, int16_t sy, uint16_t sw, uint16_t sh)
Draws the specified area from texture s. Useful for animation.
Shader (goid_t id)
Sets active shader.
BindBuffer (goid_t id)
Binds a buffer. This is only useful for buffers not used as vertex attributes.
BindFramebuffer (goid_t id, G::FramebufferType bindas)
Sets output framebuffer.
BindFramebufferComponent (goid_t id, const G::FramebufferComponent c)
Binds a texture to a specified framebuffer component slot
BindFont (goid_t f)
Set active font for the Text command. Fonts are loaded with RGL::LoadResource
Parameter (uint8_t slot, goid_t buf, G::Type type, uint8_t sz, uint32_t offset, uint32_t stride)
The equivalent of glVertexAttribPointer. Sets a vertex attribute for the active shader.
Uniformf (const char* name, float x, float y, float z, float w)
Set a uniform parameter with float values
Uniformi (const char* name, int x, int y, int z, int w)
Set a uniform parameter with int values
Uniformm (const char* name, const float* m)
Set a matrix uniform
Uniformt (const char* name, goid_t id, uint32_t slot)
Set a texture uniform
DrawArrays (G::Shape type, uint32_t start, uint32_t sz)
DrawArraysIndirect (G::Shape type, uint32_t bufoffset)
DrawArraysInstanced (G::Shape type, uint32_t start, uint32_t sz, uint32_t nInstances, uint32_t baseInstance)
DrawElements (G::Shape type, uint16_t n, G::Type itype, uint32_t offset, uint32_t baseVertex)
DrawElementsIndirect (G::Shape type, G::Type itype, uint16_t bufoffset)
DrawElementsInstanced (G::Shape type, uint16_t n, uint32_t nInstances, G::Type itype, uint32_t offset, uint32_t baseVertex, uint32_t baseInstance)
DrawRangeElements (G::Shape type, uint16_t minel, uint16_t maxel, uint16_t n, G::Type itype, uint32_t offset, uint32_t baseVertex)
These are equivalent to the GL functions with the same name. To reduce the number of combinations, the baseInstance and baseVertex parameters are merged into all calls. Set to zero to use the unbased gl call.
SaveFramebuffer (int16_t x, int16_t y, uint16_t w, uint16_t h, const char* filename, G::Texture::Format fmt, uint8_t quality)
Save a screenshot of the current framebuffer. If coordinates are all zero, the entire framebuffer area is captured. Quality parameter is for the jpeg format.