• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #pragma once
2 
3 #include "aemu/base/Tracing.h"
4 
5 #include <assert.h>
6 #include <stddef.h>
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 namespace gfxstream {
12 
13 // A helper template to extract values form the wire protocol stream
14 // and convert them to appropriate host values.
15 //
16 // The wire protocol uses 32-bit exclusively when transferring
17 // GLintptr or GLsizei values, as well as opaque handles like GLeglImage,
18 // from the guest (even when the guest is 64-bit).
19 //
20 // The corresponding host definitions depend on the host bitness. For
21 // example, GLintptr is 64-bit on linux-x86_64. The following is a set
22 // of templates that can simplify the conversion of protocol values
23 // into host ones.
24 //
25 // The most important one is:
26 //
27 //     unpack<HOST_TYPE,SIZE_TYPE>(const void* ptr)
28 //
29 // Which reads bytes from |ptr|, using |SIZE_TYPE| as the underlying
30 // sized-integer specifier (e.g. 'uint32_t'), and converting the result
31 // into a |HOST_TYPE| value. For example:
32 //
33 //     unpack<EGLImage,uint32_t>(ptr + 12);
34 //
35 // will read a 4-byte value from |ptr + 12| and convert it into
36 // an EGLImage, which is a host void*. The template detects host
37 // pointer types to perform proper type casting.
38 //
39 // TODO(digit): Add custom unpackers to handle generic opaque void* values.
40 //              and map them to unique 32-bit values.
41 
42 template <typename T, typename S>
43 struct UnpackerT {
unpackUnpackerT44     static T unpack(const void* ptr) {
45         static_assert(sizeof(T) == sizeof(S),
46                       "Bad input arguments, have to be of the same size");
47         return *(const T*)ptr;
48     }
49 };
50 
51 template <typename T, typename S>
52 struct UnpackerT<T*, S> {
53     static T* unpack(const void* ptr) {
54         return (T*)(uintptr_t)(*(const S*)ptr);
55     }
56 };
57 
58 template <>
59 struct UnpackerT<ssize_t, uint32_t> {
60     static ssize_t unpack(const void* ptr) {
61         return (ssize_t)*(const int32_t*)ptr;
62     }
63 };
64 
65 template <typename T, typename S>
66 inline T Unpack(const void* ptr) {
67     return UnpackerT<T, S>::unpack(ptr);
68 }
69 
70 // Helper classes GenericInputBuffer and GenericOutputBuffer used to ensure
71 // input and output buffers passed to EGL/GL functions are properly aligned
72 // (preventing crashes with some backends).
73 //
74 // Usage example:
75 //
76 //    GenericInputBuffer<> inputBuffer(ptrIn, sizeIn);
77 //    GenericOutputBuffer<> outputBuffer(ptrOut, sizeOut);
78 //    glDoGetStuff(inputBuffer.get(), outputBuffer.get());
79 //    outputBuffer.flush();
80 //
81 // get() will return the original value of |ptr| if it was aligned on the
82 // configured boundary (8 bytes by default). Otherwise, it will return the
83 // address of an aligned copy of the original |size| bytes starting from |ptr|.
84 //
85 // Allowed alignment values are 1, 2, 4, 8.
86 //
87 // outputBuffer.flush() copies the content of the copy back to |ptr| explictly,
88 // if needed. It is a no-op if |ptr| was aligned.
89 //
90 // Both classes try to minimize heap usage as much as possible - the first
91 // template argument defines the size of an internal array Generic*Buffer-s use
92 // if the |ptr|'s |size| is small enough. If it doesn't fit into the internal
93 // array, an aligned copy is allocated on the heap and freed in the dtor.
94 
95 template <size_t StackSize = 1024, size_t Align = 8>
96 class GenericInputBuffer {
97     static_assert(Align == 1 || Align == 2 || Align == 4 || Align == 8,
98                   "Bad alignment parameter");
99 
100 public:
101     GenericInputBuffer(const void* input, size_t size) : mOrigBuff(input) {
102         if (((uintptr_t)input & (Align - 1U)) == 0) {
103             mPtr = const_cast<void*>(input);
104         } else {
105             if (size <= StackSize) {
106                 mPtr = &mArray[0];
107             } else {
108                 mPtr = malloc(size);
109             }
110             memcpy(mPtr, input, size);
111         }
112     }
113 
114     ~GenericInputBuffer() {
115         if (mPtr != mOrigBuff && mPtr != &mArray[0]) {
116             free(mPtr);
117         }
118     }
119 
120     const void* get() const { return mPtr; }
121 
122 private:
123     // A pointer to the aligned buffer, might point either to mOrgBuf, to mArray
124     // start or to a heap-allocated chunk of data.
125     void* mPtr;
126     // Original buffer.
127     const void* mOrigBuff;
128     // Inplace aligned array for small enough buffers.
129     char __attribute__((__aligned__(Align))) mArray[StackSize];
130 };
131 
132 template <size_t StackSize = 1024, size_t Align = 8>
133 class GenericOutputBuffer {
134     static_assert(Align == 1 || Align == 2 || Align == 4 || Align == 8,
135                   "Bad alignment parameter");
136 
137 public:
138     GenericOutputBuffer(unsigned char* ptr, size_t size) :
139             mOrigBuff(ptr), mSize(size) {
140         if (((uintptr_t)ptr & (Align - 1U)) == 0) {
141             mPtr = ptr;
142         } else {
143             if (size <= StackSize) {
144                 mPtr = &mArray[0];
145             } else {
146                 mPtr = calloc(1, size);
147             }
148         }
149     }
150 
151     ~GenericOutputBuffer() {
152         if (mPtr != mOrigBuff && mPtr != &mArray[0]) {
153             free(mPtr);
154         }
155     }
156 
157     void* get() const { return mPtr; }
158 
159     void flush() {
160         if (mPtr != mOrigBuff) {
161             memcpy(mOrigBuff, mPtr, mSize);
162         }
163     }
164 
165 private:
166     // A pointer to the aligned buffer, might point either to mOrgBuf, to mArray
167     // start or to a heap-allocated chunk of data.
168     void* mPtr;
169     // Original buffer.
170     unsigned char* mOrigBuff;
171     // Original buffer size.
172     size_t mSize;
173     // Inplace array for small enough buffers.
174     unsigned char __attribute__((__aligned__(Align))) mArray[StackSize];
175 };
176 
177 // Pin the defaults for the commonly used type names
178 using InputBuffer = GenericInputBuffer<>;
179 using OutputBuffer = GenericOutputBuffer<>;
180 
181 }  // namespace gfxstream
182