#ifndef EMUGL_PROTOCOL_UTILS_H #define EMUGL_PROTOCOL_UTILS_H #include #include namespace emugl { // Helper macro #define COMPILE_ASSERT(cond) static char kAssert##__LINE__[1 - 2 * !(cond)] __attribute__((unused)) = { 0 } // Helper template: is_pointer. // is_pointer::value is true iff |T| is a pointer type. template struct is_pointer { static const bool value = false; }; template struct is_pointer { static const bool value = true; }; // A helper template to extract values form the wire protocol stream // and convert them to appropriate host values. // // The wire protocol uses 32-bit exclusively when transferring // GLintptr or GLsizei values, as well as opaque handles like GLeglImage, // from the guest (even when the guest is 64-bit). // // The corresponding host definitions depend on the host bitness. For // example, GLintptr is 64-bit on linux-x86_64. The following is a set // of templates that can simplify the conversion of protocol values // into host ones. // // The most important one is: // // unpack(const void* ptr) // // Which reads bytes from |ptr|, using |SIZE_TYPE| as the underlying // sized-integer specifier (e.g. 'uint32_t'), and converting the result // into a |HOST_TYPE| value. For example: // // unpack(ptr + 12); // // will read a 4-byte value from |ptr + 12| and convert it into // an EGLImage, which is a host void*. The template detects host // pointer types to perform proper type casting. // // TODO(digit): Add custom unpackers to handle generic opaque void* values. // and map them to unique 32-bit values. template struct UnpackerT {}; template struct UnpackerT { static inline T unpack(const void* ptr) { COMPILE_ASSERT(sizeof(T) == sizeof(S)); return (T)(*(S*)(ptr)); } }; template struct UnpackerT { static inline T unpack(const void* ptr) { return (T)(uintptr_t)(*(S*)(ptr)); } }; template <> struct UnpackerT { static inline float unpack(const void* ptr) { union { float f; uint32_t u; } v; v.u = *(uint32_t*)(ptr); return v.f; } }; template <> struct UnpackerT { static inline double unpack(const void* ptr) { union { double d; uint32_t u; } v; v.u = *(uint64_t*)(ptr); return v.d; } }; template <> struct UnpackerT { static inline ssize_t unpack(const void* ptr) { return (ssize_t)*(int32_t*)(ptr); } }; template inline T Unpack(const void* ptr) { return UnpackerT::value>::unpack(ptr); } } // namespace emugl #endif // EMUGL_PROTOCOL_UTILS_H