TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / external / android-emugl / shared / OpenglCodecCommon / ProtocolUtils.h
1 #ifndef EMUGL_PROTOCOL_UTILS_H
2 #define EMUGL_PROTOCOL_UTILS_H
3
4 #include <stddef.h>
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 namespace emugl {
10
11 // Helper macro
12 #define COMPILE_ASSERT(cond)  static char kAssert##__LINE__[1 - 2 * !(cond)] __attribute__((unused)) = { 0 }
13
14 // Helper template: is_pointer.
15 // is_pointer<T>::value is true iff |T| is a pointer type.
16 template <typename T> struct is_pointer {
17     static const bool value = false;
18 };
19
20 template <typename T> struct is_pointer<T*> {
21     static const bool value = true;
22 };
23
24 // A helper template to extract values form the wire protocol stream
25 // and convert them to appropriate host values.
26 //
27 // The wire protocol uses 32-bit exclusively when transferring
28 // GLintptr or GLsizei values, as well as opaque handles like GLeglImage,
29 // from the guest (even when the guest is 64-bit).
30 //
31 // The corresponding host definitions depend on the host bitness. For
32 // example, GLintptr is 64-bit on linux-x86_64. The following is a set
33 // of templates that can simplify the conversion of protocol values
34 // into host ones.
35 //
36 // The most important one is:
37 //
38 //     unpack<HOST_TYPE,SIZE_TYPE>(const void* ptr)
39 //
40 // Which reads bytes from |ptr|, using |SIZE_TYPE| as the underlying
41 // sized-integer specifier (e.g. 'uint32_t'), and converting the result
42 // into a |HOST_TYPE| value. For example:
43 //
44 //     unpack<EGLImage,uint32_t>(ptr + 12);
45 //
46 // will read a 4-byte value from |ptr + 12| and convert it into
47 // an EGLImage, which is a host void*. The template detects host
48 // pointer types to perform proper type casting.
49 //
50 // TODO(digit): Add custom unpackers to handle generic opaque void* values.
51 //              and map them to unique 32-bit values.
52
53 template <typename T, typename S, bool IS_POINTER>
54 struct UnpackerT {};
55
56 template <typename T, typename S>
57 struct UnpackerT<T,S,false> {
58     static inline T unpack(const void* ptr) {
59         COMPILE_ASSERT(sizeof(T) == sizeof(S));
60         return (T)(*(S*)(ptr));
61     }
62 };
63
64 template <typename T, typename S>
65 struct UnpackerT<T,S,true> {
66     static inline T unpack(const void* ptr) {
67         return (T)(uintptr_t)(*(S*)(ptr));
68     }
69 };
70
71 template <>
72 struct UnpackerT<float,uint32_t,false> {
73     static inline float unpack(const void* ptr) {
74         union {
75             float f;
76             uint32_t u;
77         } v;
78         v.u = *(uint32_t*)(ptr);
79         return v.f;
80     }
81 };
82
83 template <>
84 struct UnpackerT<double,uint64_t,false> {
85     static inline double unpack(const void* ptr) {
86         union {
87             double d;
88             uint32_t u;
89         } v;
90         v.u = *(uint64_t*)(ptr);
91         return v.d;
92     }
93 };
94
95 template <>
96 struct UnpackerT<ssize_t,uint32_t,false> {
97     static inline ssize_t unpack(const void* ptr) {
98         return (ssize_t)*(int32_t*)(ptr);
99     }
100 };
101
102 template <typename T, typename S>
103 inline T Unpack(const void* ptr) {
104     return UnpackerT<T, S, is_pointer<T>::value>::unpack(ptr);
105 }
106
107 // Helper class used to ensure input buffers passed to EGL/GL functions
108 // are properly aligned (preventing crashes with some backends).
109 // Usage example:
110 //
111 //    InputBuffer inputBuffer(ptr, size);
112 //    glDoStuff(inputBuffer.get());
113 //
114 // inputBuffer.get() will return the original value of |ptr| if it was
115 // aligned on an 8-byte boundary. Otherwise, it will return the address
116 // of an aligned heap-allocated copy of the original |size| bytes starting
117 // from |ptr|. The heap block is released at scope exit.
118 class InputBuffer {
119 public:
120     InputBuffer(const void* input, size_t size, size_t align = 8) :
121             mBuff(input), mIsCopy(false) {
122         if (((uintptr_t)input & (align - 1U)) != 0) {
123             void* newBuff = malloc(size);
124             memcpy(newBuff, input, size);
125             mBuff = newBuff;
126             mIsCopy = true;
127         }
128     }
129
130     ~InputBuffer() {
131         if (mIsCopy) {
132             free((void*)mBuff);
133         }
134     }
135
136     const void* get() const {
137         return mBuff;
138     }
139
140 private:
141     const void* mBuff;
142     bool mIsCopy;
143 };
144
145 // Helper class used to ensure that output buffers passed to EGL/GL functions
146 // are aligned on 8-byte addresses.
147 // Usage example:
148 //
149 //    ptr = stream->alloc(size);
150 //    OutputBuffer outputBuffer(ptr, size);
151 //    glGetStuff(outputBuffer.get());
152 //    outputBuffer.flush();
153 //
154 // outputBuffer.get() returns the original value of |ptr| if it was already
155 // aligned on an 8=byte boundary. Otherwise, it returns the size of an heap
156 // allocated zeroed buffer of |size| bytes.
157 //
158 // outputBuffer.flush() copies the content of the heap allocated buffer back
159 // to |ptr| explictly, if needed. If a no-op if |ptr| was aligned.
160 class OutputBuffer {
161 public:
162     OutputBuffer(unsigned char* ptr, size_t size, size_t align = 8) :
163             mOrgBuff(ptr), mBuff(ptr), mSize(size) {
164         if (((uintptr_t)ptr & (align - 1U)) != 0) {
165             void* newBuff = calloc(1, size);
166             mBuff = newBuff;
167         }
168     }
169
170     ~OutputBuffer() {
171         if (mBuff != mOrgBuff) {
172             free(mBuff);
173         }
174     }
175
176     void* get() const {
177         return mBuff;
178     }
179
180     void flush() {
181         if (mBuff != mOrgBuff) {
182             memcpy(mOrgBuff, mBuff, mSize);
183         }
184     }
185 private:
186     unsigned char* mOrgBuff;
187     void* mBuff;
188     size_t mSize;
189 };
190
191 }  // namespace emugl
192
193 #endif  // EMUGL_PROTOCOL_UTILS_H