diff options
author | David 'Digit' Turner <digit@google.com> | 2014-09-13 04:11:11 +0200 |
---|---|---|
committer | David 'Digit' Turner <digit@google.com> | 2014-09-16 02:27:23 +0200 |
commit | 5998eb01070760ecca8eb5fae62e056db482f535 (patch) | |
tree | 6467d074aa77b4ef29f561200c77f034118ef628 /emulator/opengl/shared | |
parent | a9937510fd549108ef9533b61533b540c9274052 (diff) | |
download | sdk-5998eb01070760ecca8eb5fae62e056db482f535.zip sdk-5998eb01070760ecca8eb5fae62e056db482f535.tar.gz sdk-5998eb01070760ecca8eb5fae62e056db482f535.tar.bz2 |
emulator/opengl/emugen: Use templates to read values from stream.
The decoder didn't properly handle GLsizeiptr and GLintptr values, which
are always 32-bit on the wire, but can be 64-bit on the host. I.e. it
did something like that to read them from the stream:
*(GLsizeiptr*)(ptr + offset)
This fixes the issue by using templates to generate host-type-specific
functions that properly read data from the stream and convert it to the
appropriate host type.
Change-Id: I75749bd715456ca143eb1713498f7cf635918801
Diffstat (limited to 'emulator/opengl/shared')
-rw-r--r-- | emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h b/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h new file mode 100644 index 0000000..1198bd1 --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/ProtocolUtils.h @@ -0,0 +1,107 @@ +#ifndef EMUGL_PROTOCOL_UTILS_H +#define EMUGL_PROTOCOL_UTILS_H + +#include <stddef.h> +#include <stdint.h> + +namespace emugl { + +// Helper macro +#define COMPILE_ASSERT(cond) static char kAssert##__LINE__[1 - 2 * !(cond)] __attribute__((unused)) = { 0 } + +// Helper template: is_pointer. +// is_pointer<T>::value is true iff |T| is a pointer type. +template <typename T> struct is_pointer { + static const bool value = false; +}; + +template <typename T> struct is_pointer<T*> { + 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<HOST_TYPE,SIZE_TYPE>(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<EGLImage,uint32_t>(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 <typename T, typename S, bool IS_POINTER> +struct UnpackerT {}; + +template <typename T, typename S> +struct UnpackerT<T,S,false> { + static inline T unpack(const void* ptr) { + COMPILE_ASSERT(sizeof(T) == sizeof(S)); + return (T)(*(S*)(ptr)); + } +}; + +template <typename T, typename S> +struct UnpackerT<T,S,true> { + static inline T unpack(const void* ptr) { + return (T)(uintptr_t)(*(S*)(ptr)); + } +}; + +template <> +struct UnpackerT<float,uint32_t,false> { + 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<double,uint64_t,false> { + 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<ssize_t,uint32_t,false> { + static inline ssize_t unpack(const void* ptr) { + return (ssize_t)*(int32_t*)(ptr); + } +}; + +template <typename T, typename S> +inline T Unpack(const void* ptr) { + return UnpackerT<T, S, is_pointer<T>::value>::unpack(ptr); +} + +} // namespace emugl + +#endif // EMUGL_PROTOCOL_UTILS_H |