xref: /aosp_15_r20/external/mesa3d/src/gfxstream/aemu/Stream.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2019 Google
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "Stream.h"
7 
8 #include <assert.h>
9 #include <string.h>
10 
11 namespace gfxstream {
12 namespace aemu {
13 
putByte(uint8_t value)14 void Stream::putByte(uint8_t value) { write(&value, 1U); }
15 
getByte()16 uint8_t Stream::getByte() {
17     uint8_t value[1] = {0};
18     read(value, 1U);
19     return value[0];
20 }
21 
putBe16(uint16_t value)22 void Stream::putBe16(uint16_t value) {
23     uint8_t b[2] = {(uint8_t)(value >> 8), (uint8_t)value};
24     write(b, 2U);
25 }
26 
getBe16()27 uint16_t Stream::getBe16() {
28     uint8_t b[2] = {0, 0};
29     read(b, 2U);
30     return ((uint16_t)b[0] << 8) | (uint16_t)b[1];
31 }
32 
putBe32(uint32_t value)33 void Stream::putBe32(uint32_t value) {
34     uint8_t b[4] = {(uint8_t)(value >> 24), (uint8_t)(value >> 16), (uint8_t)(value >> 8),
35                     (uint8_t)value};
36     write(b, 4U);
37 }
38 
getBe32()39 uint32_t Stream::getBe32() {
40     uint8_t b[4] = {0, 0, 0, 0};
41     read(b, 4U);
42     return ((uint32_t)b[0] << 24) | ((uint32_t)b[1] << 16) | ((uint32_t)b[2] << 8) | (uint32_t)b[3];
43 }
44 
putBe64(uint64_t value)45 void Stream::putBe64(uint64_t value) {
46     uint8_t b[8] = {(uint8_t)(value >> 56), (uint8_t)(value >> 48), (uint8_t)(value >> 40),
47                     (uint8_t)(value >> 32), (uint8_t)(value >> 24), (uint8_t)(value >> 16),
48                     (uint8_t)(value >> 8),  (uint8_t)value};
49     write(b, 8U);
50 }
51 
getBe64()52 uint64_t Stream::getBe64() {
53     uint8_t b[8] = {0, 0, 0, 0, 0, 0, 0, 0};
54     read(b, 8U);
55     return ((uint64_t)b[0] << 56) | ((uint64_t)b[1] << 48) | ((uint64_t)b[2] << 40) |
56            ((uint64_t)b[3] << 32) | ((uint64_t)b[4] << 24) | ((uint64_t)b[5] << 16) |
57            ((uint64_t)b[6] << 8) | (uint64_t)b[7];
58 }
59 
putFloat(float v)60 void Stream::putFloat(float v) {
61     union {
62         float f;
63         uint8_t bytes[sizeof(float)];
64     } u;
65     u.f
66     = v;
67     this->write(u.bytes, sizeof(u.bytes));
68 }
69 
getFloat()70 float Stream::getFloat() {
71     union {
72         float f;
73         uint8_t bytes[sizeof(float)];
74     } u;
75     this->read(u.bytes, sizeof(u.bytes));
76     return u.f;
77 }
78 
putString(const char * str)79 void Stream::putString(const char* str) { putString(str, strlen(str)); }
80 
putString(const char * str,size_t len)81 void Stream::putString(const char* str, size_t len) {
82     this->putBe32(len);
83     this->write(str, len);
84 }
85 
putString(const std::string & str)86 void Stream::putString(const std::string& str) { putString(str.c_str()); }
87 
getString()88 std::string Stream::getString() {
89     std::string result;
90     size_t len = this->getBe32();
91     if (len > 0) {
92         result.resize(len);
93         if (this->read(&result[0], len) != static_cast<ssize_t>(len)) {
94             result.clear();
95         }
96     }
97 #ifdef _WIN32
98     else {
99         // std::string in GCC's STL still uses copy on write implementation
100         // with a single shared buffer for an empty string. Its dtor has
101         // a check for that shared buffer, and it deallocates memory only if
102         // the current string's instance address != shared empty string address
103         // Unfortunately, in Windows DLLs each DLL has its own copy of this
104         // empty string (that's just the way Windows DLLs work), so if this
105         // code creates an empty string and passes it over into another module,
106         // that module's std::string::~string() will compare address with its
107         // empty string object, find that they are different and will try to
108         // free() a static object.
109         // To mitigate it we make sure the string allocates something, so it
110         // isn't empty internally and dtor is OK to delete the storage.
111         result.reserve(1);
112     }
113 #endif
114     return result;
115 }
116 
putPackedNum(uint64_t num)117 void Stream::putPackedNum(uint64_t num) {
118     do {
119         auto byte = uint8_t(num & 0x7f);
120         num >>= 7;
121         if (num) {
122             byte |= 0x80;
123         }
124         putByte(byte);
125     } while (num != 0);
126 }
127 
getPackedNum()128 uint64_t Stream::getPackedNum() {
129     uint64_t res = 0;
130     uint8_t byte;
131     int i = 0;
132     do {
133         byte = getByte();
134         res |= uint64_t(byte & 0x7f) << (i++ * 7);
135     } while (byte & 0x80 && i < 10);
136     return res;
137 }
138 
putPackedSignedNum(int64_t num)139 void Stream::putPackedSignedNum(int64_t num) {
140     if (num >= 0) {
141         assert((uint64_t(num) & (1ULL << 63)) == 0);
142         putPackedNum(uint64_t(num) << 1);
143     } else {
144         assert((uint64_t(-num) & (1ULL << 63)) == 0);
145         putPackedNum((uint64_t(-num) << 1) | 1);
146     }
147 }
148 
getPackedSignedNum()149 int64_t Stream::getPackedSignedNum() {
150     auto num = getPackedNum();
151     auto sign = num & 1;
152     return sign ? -int64_t(num >> 1) : (num >> 1);
153 }
154 
155 // Static big-endian conversions
156 
157 // the |v| pointer is unlikely to be aligned---use memcpy throughout
158 
toByte(uint8_t *)159 void Stream::toByte(uint8_t*) {}  // no conversion
160 
toBe16(uint8_t * v)161 void Stream::toBe16(uint8_t* v) {
162     uint16_t value;
163     memcpy(&value, v, sizeof(uint16_t));
164     uint8_t b[2] = {(uint8_t)(value >> 8), (uint8_t)value};
165     memcpy(v, b, sizeof(uint16_t));
166 }
167 
toBe32(uint8_t * v)168 void Stream::toBe32(uint8_t* v) {
169     uint32_t value;
170     memcpy(&value, v, sizeof(uint32_t));
171     uint8_t b[4] = {(uint8_t)(value >> 24), (uint8_t)(value >> 16), (uint8_t)(value >> 8),
172                     (uint8_t)value};
173     memcpy(v, b, sizeof(uint32_t));
174 }
175 
toBe64(uint8_t * v)176 void Stream::toBe64(uint8_t* v) {
177     uint64_t value;
178     memcpy(&value, v, sizeof(uint64_t));
179     uint8_t b[8] = {(uint8_t)(value >> 56), (uint8_t)(value >> 48), (uint8_t)(value >> 40),
180                     (uint8_t)(value >> 32), (uint8_t)(value >> 24), (uint8_t)(value >> 16),
181                     (uint8_t)(value >> 8),  (uint8_t)value};
182     memcpy(v, b, sizeof(uint64_t));
183 }
184 
fromByte(uint8_t *)185 void Stream::fromByte(uint8_t*) {}  // no conversion
186 
fromBe16(uint8_t * v)187 void Stream::fromBe16(uint8_t* v) {
188     uint8_t b[2];
189     memcpy(b, v, sizeof(uint16_t));
190     uint16_t value = ((uint16_t)b[0] << 8) | (uint16_t)b[1];
191     memcpy(v, &value, sizeof(uint16_t));
192 }
193 
fromBe32(uint8_t * v)194 void Stream::fromBe32(uint8_t* v) {
195     uint8_t b[4];
196     memcpy(b, v, sizeof(uint32_t));
197     uint32_t value =
198         ((uint32_t)b[0] << 24) | ((uint32_t)b[1] << 16) | ((uint32_t)b[2] << 8) | (uint32_t)b[3];
199     memcpy(v, &value, sizeof(uint32_t));
200 }
201 
fromBe64(uint8_t * v)202 void Stream::fromBe64(uint8_t* v) {
203     uint8_t b[8];
204     memcpy(b, v, sizeof(uint64_t));
205     uint64_t value = ((uint64_t)b[0] << 56) | ((uint64_t)b[1] << 48) | ((uint64_t)b[2] << 40) |
206                      ((uint64_t)b[3] << 32) | ((uint64_t)b[4] << 24) | ((uint64_t)b[5] << 16) |
207                      ((uint64_t)b[6] << 8) | (uint64_t)b[7];
208     memcpy(v, &value, sizeof(uint64_t));
209 }
210 
saveStringArray(Stream * stream,const char * const * strings,uint32_t count)211 void saveStringArray(Stream* stream, const char* const* strings, uint32_t count) {
212     stream->putBe32(count);
213     for (uint32_t i = 0; i < count; ++i) {
214         stream->putString(strings[i]);
215     }
216 }
217 
218 }  // namespace aemu
219 }  // namespace gfxstream
220