1 // Copyright (C) 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "GfxStreamAgents.h"
15
16 #include <stdint.h> // for uint32_t
17 #include <stdio.h> // for fprintf
18
19 #include <map> // for map, __ma...
20 #include <utility> // for pair
21
22 #include "host-common/HostmemIdMapping.h" // for android_e...
23 #include "host-common/MultiDisplay.h" // for MultiDisp...
24 #include "host-common/multi_display_agent.h" // for QAndroidM...
25 #include "host-common/vm_operations.h" // for SnapshotC...
26 #include "host-common/window_agent.h" // for WindowMes...
27 #include "host-common/misc.h"
28
29 #ifdef _DEBUG
30 #define DEBUG_LOG(fd, fmt, ...) fprintf(fd, fmt, __VA_ARGS__);
31 #else
32 #define DEBUG_LOG(fd, fmt, ...)
33 #endif
34
35 static std::map<uint32_t, android::MultiDisplayInfo> mMultiDisplay;
36
37 using namespace android;
38
39 static const QAndroidMultiDisplayAgent sMultiDisplayAgent = {
40 .setMultiDisplay = [](uint32_t id,
41 int32_t x,
42 int32_t y,
43 uint32_t w,
44 uint32_t h,
45 uint32_t dpi,
46 uint32_t flag,
__anon99f56eaf0102() 47 bool add) -> int {
48 return 0;
49 },
50 .getMultiDisplay = [](uint32_t id,
51 int32_t* x,
52 int32_t* y,
53 uint32_t* w,
54 uint32_t* h,
55 uint32_t* dpi,
56 uint32_t* flag,
__anon99f56eaf0202() 57 bool* enabled) -> bool {
58 if (mMultiDisplay.find(id) == mMultiDisplay.end()) {
59 if (enabled) {
60 *enabled = false;
61 }
62 return false;
63 }
64 if (x) {
65 *x = mMultiDisplay[id].pos_x;
66 }
67 if (y) {
68 *y = mMultiDisplay[id].pos_y;
69 }
70 if (w) {
71 *w = mMultiDisplay[id].width;
72 }
73 if (h) {
74 *h = mMultiDisplay[id].height;
75 }
76 if (dpi) {
77 *dpi = mMultiDisplay[id].dpi;
78 }
79 if (flag) {
80 *flag = mMultiDisplay[id].flag;
81 }
82 if (enabled) {
83 *enabled = mMultiDisplay[id].enabled;
84 }
85 return true;
86 },
87 .getNextMultiDisplay = [](int32_t start_id,
88 uint32_t* id,
89 int32_t* x,
90 int32_t* y,
91 uint32_t* w,
92 uint32_t* h,
93 uint32_t* dpi,
94 uint32_t* flag,
__anon99f56eaf0302() 95 uint32_t* cb) -> bool {
96 uint32_t key;
97 std::map<uint32_t, android::MultiDisplayInfo>::iterator i;
98 if (start_id < 0) {
99 key = 0;
100 } else {
101 key = start_id + 1;
102 }
103 i = mMultiDisplay.lower_bound(key);
104 if (i == mMultiDisplay.end()) {
105 return false;
106 } else {
107 if (id) {
108 *id = i->first;
109 }
110 if (x) {
111 *x = i->second.pos_x;
112 }
113 if (y) {
114 *y = i->second.pos_y;
115 }
116 if (w) {
117 *w = i->second.width;
118 }
119 if (h) {
120 *h = i->second.height;
121 }
122 if (dpi) {
123 *dpi = i->second.dpi;
124 }
125 if (flag) {
126 *flag = i->second.flag;
127 }
128 if (cb) {
129 *cb = i->second.cb;
130 }
131 return true;
132 }
133 },
__anon99f56eaf0402() 134 .isMultiDisplayEnabled = [](void) -> bool {
135 return mMultiDisplay.size() > 1;
136 },
__anon99f56eaf0502() 137 .getCombinedDisplaySize = [](uint32_t* width, uint32_t* height) {},
138 .multiDisplayParamValidate = [](uint32_t id,
139 uint32_t w,
140 uint32_t h,
141 uint32_t dpi,
__anon99f56eaf0602() 142 uint32_t flag) -> bool { return true; },
143 .translateCoordination =
__anon99f56eaf0702() 144 [](uint32_t* x, uint32_t* y, uint32_t* displayId) -> bool {
145 return true;
146 },
__anon99f56eaf0802() 147 .setGpuMode = [](bool isGuestMode, uint32_t w, uint32_t h) {},
__anon99f56eaf0902() 148 .createDisplay = [](uint32_t* displayId) -> int {
149 if (displayId == nullptr) {
150 ERR("cannot create display, null displayId pointer");
151 return -1;
152 }
153 if (mMultiDisplay.size() >= MultiDisplay::s_maxNumMultiDisplay) {
154 ERR("cannot create more displays, exceeding limits %d",
155 MultiDisplay::s_maxNumMultiDisplay);
156 return -1;
157 }
158 if (mMultiDisplay.find(*displayId) != mMultiDisplay.end()) {
159 return 0;
160 }
161 // displays created by internal rcCommands
162 if (*displayId == MultiDisplay::s_invalidIdMultiDisplay) {
163 for (int i = MultiDisplay::s_displayIdInternalBegin; i < MultiDisplay::s_maxNumMultiDisplay; i++) {
164 if (mMultiDisplay.find(i) == mMultiDisplay.end()) {
165 *displayId = i;
166 break;
167 }
168 }
169 }
170 if (*displayId == MultiDisplay::s_invalidIdMultiDisplay) {
171 ERR("cannot create more internaldisplays, exceeding limits %d",
172 MultiDisplay::s_maxNumMultiDisplay - MultiDisplay::s_displayIdInternalBegin);
173 return -1;
174 }
175
176 mMultiDisplay.emplace(*displayId, android::MultiDisplayInfo());
177 return 0;
178 },
__anon99f56eaf0a02() 179 .destroyDisplay = [](uint32_t displayId) -> int {
180 mMultiDisplay.erase(displayId);
181 return 0;
182 },
183 .setDisplayPose = [](uint32_t displayId,
184 int32_t x,
185 int32_t y,
186 uint32_t w,
187 uint32_t h,
__anon99f56eaf0b02() 188 uint32_t dpi) -> int {
189 if (mMultiDisplay.find(displayId) == mMultiDisplay.end()) {
190 ERR("cannot find display %d", displayId);
191 return -1;
192 }
193 mMultiDisplay[displayId].pos_x = x;
194 mMultiDisplay[displayId].pos_y = y;
195 mMultiDisplay[displayId].width = w;
196 mMultiDisplay[displayId].height = h;
197 mMultiDisplay[displayId].dpi = dpi;
198 return 0;
199 },
200 .getDisplayPose = [](uint32_t displayId,
201 int32_t* x,
202 int32_t* y,
203 uint32_t* w,
__anon99f56eaf0c02() 204 uint32_t* h) -> int {
205 if (mMultiDisplay.find(displayId) == mMultiDisplay.end()) {
206 ERR("cannot find display %d", displayId);
207 return -1;
208 }
209 if (x)
210 *x = mMultiDisplay[displayId].pos_x;
211 if (y)
212 *y = mMultiDisplay[displayId].pos_y;
213 if (w)
214 *w = mMultiDisplay[displayId].width;
215 if (h)
216 *h = mMultiDisplay[displayId].height;
217 return 0;
218 },
219 .getDisplayColorBuffer = [](uint32_t displayId,
__anon99f56eaf0d02() 220 uint32_t* colorBuffer) -> int {
221 if (mMultiDisplay.find(displayId) == mMultiDisplay.end()) {
222 ERR("cannot find display %d", displayId);
223 return -1;
224 }
225 *colorBuffer = mMultiDisplay[displayId].cb;
226 return 0;
227 },
228 .getColorBufferDisplay = [](uint32_t colorBuffer,
__anon99f56eaf0e02() 229 uint32_t* displayId) -> int {
230 for (const auto& iter : mMultiDisplay) {
231 if (iter.second.cb == colorBuffer) {
232 *displayId = iter.first;
233 return 0;
234 }
235 }
236 return -1;
237 },
238 .setDisplayColorBuffer = [](uint32_t displayId,
__anon99f56eaf0f02() 239 uint32_t colorBuffer) -> int {
240 if (mMultiDisplay.find(displayId) == mMultiDisplay.end()) {
241 ERR("Unable to set display color buffer for non existing display: %d", displayId);
242 return -1;
243 }
244 mMultiDisplay[displayId].cb = colorBuffer;
245 return 0;
246 },
__anon99f56eaf1002() 247 .isPixelFold = [] () {
248 return false;
249 },
250 };
251
252 static bool sIsFolded = false;
253
254 static const QAndroidEmulatorWindowAgent sQAndroidEmulatorWindowAgent = {
255 .getEmulatorWindow =
__anon99f56eaf1102() 256 [](void) {
257 DEBUG_LOG(stderr,
258 "window-agent-GfxStream-impl: "
259 ".getEmulatorWindow\n");
260 return (EmulatorWindow*)nullptr;
261 },
262 .rotate90Clockwise =
__anon99f56eaf1202() 263 [](void) {
264 DEBUG_LOG(stderr,
265 "window-agent-GfxStream-impl: "
266 ".rotate90Clockwise\n");
267 return true;
268 },
269 .rotate =
__anon99f56eaf1302() 270 [](int rotation) {
271 DEBUG_LOG(stderr,
272 "window-agent-GfxStream-impl: "
273 ".rotate90Clockwise\n");
274 return true;
275 },
276 .getRotation =
__anon99f56eaf1402() 277 [](void) {
278 DEBUG_LOG(stderr,
279 "window-agent-GfxStream-impl: .getRotation\n");
280 return (int)SKIN_ROTATION_0;
281 },
282 .showMessage =
__anon99f56eaf1502() 283 [](const char* message, WindowMessageType type, int timeoutMs) {
284 DEBUG_LOG(stderr,
285 "window-agent-GfxStream-impl: .showMessage %s\n",
286 message);
287 },
288 .showMessageWithDismissCallback =
289 [](const char* message,
290 WindowMessageType type,
291 const char* dismissText,
292 void* context,
293 void (*func)(void*),
__anon99f56eaf1602() 294 int timeoutMs) {
295 DEBUG_LOG(stderr,
296 "window-agent-GfxStream-impl: "
297 ".showMessageWithDismissCallback %s\n",
298 message);
299 },
300 .fold =
__anon99f56eaf1702() 301 [](bool is_fold) -> bool {
302 DEBUG_LOG(stderr, "window-agent-GfxStream-impl: .fold %d\n",
303 is_fold);
304 sIsFolded = is_fold;
305 return true;
306 },
__anon99f56eaf1802() 307 .isFolded = [](void) -> bool { return sIsFolded; },
__anon99f56eaf1902() 308 .getFoldedArea = [](int* x, int* y, int* w, int* h) -> bool {
309 DEBUG_LOG(stderr, "window-agent-GfxStream-impl: .getFoldedArea\n");
310 return true;
311 },
__anon99f56eaf1a02() 312 .updateFoldablePostureIndicator = [](bool) {
313 DEBUG_LOG(stderr, "window-agent-GfxStream-impl: updateFoldablePostureIndicator\n");
314 },
315 .setUIDisplayRegion =
__anon99f56eaf1b02() 316 [](int x_offset, int y_offset, int w, int h, bool ignoreOrientation) {
317 DEBUG_LOG(stderr,
318 "window-agent-GfxStream-impl: .setUIDisplayRegion "
319 "%d %d %dx%d\n",
320 x_offset, y_offset, w, h);
321 },
322 .getMultiDisplay = 0,
__anon99f56eaf1c02() 323 .setNoSkin = [](void) {},
__anon99f56eaf1d02() 324 .restoreSkin = [](void) {},
325 .updateUIMultiDisplayPage =
__anon99f56eaf1e02() 326 [](uint32_t id) {
327 DEBUG_LOG(stderr, "updateMultiDisplayPage\n");
328 },
329 .getMonitorRect =
__anon99f56eaf1f02() 330 [](uint32_t* w, uint32_t* h) -> bool {
331 if (w)
332 *w = 2500;
333 if (h)
334 *h = 1600;
335 return true;
336 },
337 };
338
339 static const QAndroidVmOperations sQAndroidVmOperations =
340 {
__anon99f56eaf2002() 341 .vmStop = []() -> bool {
342 DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm stop\n");
343 return true;
344 },
__anon99f56eaf2102() 345 .vmStart = []() -> bool {
346 DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm start\n");
347 return true;
348 },
__anon99f56eaf2202() 349 .vmReset = []() { DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm reset\n"); },
__anon99f56eaf2302() 350 .vmShutdown = []() { DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm reset\n"); },
__anon99f56eaf2402() 351 .vmPause = []() -> bool {
352 DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm pause\n");
353 return true;
354 },
__anon99f56eaf2502() 355 .vmResume = []() -> bool {
356 DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm resume\n");
357 return true;
358 },
__anon99f56eaf2602() 359 .vmIsRunning = []() -> bool {
360 DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm is running\n");
361 return true;
362 },
__anon99f56eaf2702() 363 .snapshotList = [](void*, LineConsumerCallback, LineConsumerCallback) -> bool {
364 DEBUG_LOG(stderr, "goldfish-opengl vm ops: snapshot list\n");
365 return true;
366 },
__anon99f56eaf2802() 367 .snapshotSave = [](const char* name, void* opaque, LineConsumerCallback) -> bool {
368 DEBUG_LOG(stderr, "gfxstream vm ops: snapshot save\n");
369 return true;
370 },
__anon99f56eaf2902() 371 .snapshotLoad = [](const char* name, void* opaque, LineConsumerCallback) -> bool {
372 DEBUG_LOG(stderr, "gfxstream vm ops: snapshot load\n");
373 return true;
374 },
375 .snapshotDelete = [](const char* name, void* opaque,
__anon99f56eaf2a02() 376 LineConsumerCallback errConsumer) -> bool {
377 DEBUG_LOG(stderr, "goldfish-opengl vm ops: snapshot delete\n");
378 return true;
379 },
__anon99f56eaf2b02() 380 .snapshotRemap = [](bool shared, void* opaque, LineConsumerCallback errConsumer) -> bool {
381 DEBUG_LOG(stderr, "goldfish-opengl vm ops: snapshot remap\n");
382 return true;
383 },
384 .snapshotExport = [](const char* snapshot, const char* dest, void* opaque,
__anon99f56eaf2c02() 385 LineConsumerCallback errConsumer) -> bool {
386 DEBUG_LOG(stderr, "goldfish-opengl vm ops: snapshot export image\n");
387 return true;
388 },
389 .setSnapshotCallbacks =
__anon99f56eaf2d02() 390 [](void* opaque, const SnapshotCallbacks* callbacks) {
391 DEBUG_LOG(stderr, "goldfish-opengl vm ops: set snapshot callbacks\n");
392 },
393 .mapUserBackedRam =
__anon99f56eaf2e02() 394 [](uint64_t gpa, void* hva, uint64_t size) {
395 DEBUG_LOG(stderr, "%s: map user backed ram\n", __func__);
396 },
397 .unmapUserBackedRam =
__anon99f56eaf2f02() 398 [](uint64_t gpa, uint64_t size) {
399 DEBUG_LOG(stderr, "%s: unmap user backed ram\n", __func__);
400 },
401 .getVmConfiguration =
__anon99f56eaf3002() 402 [](VmConfiguration* out) {
403 DEBUG_LOG(stderr, "goldfish-opengl vm ops: get vm configuration\n");
404 },
405 .setFailureReason =
__anon99f56eaf3102() 406 [](const char* name, int failureReason) {
407 DEBUG_LOG(stderr, "goldfish-opengl vm ops: set failure reason\n");
408 },
__anon99f56eaf3202() 409 .setExiting = []() { DEBUG_LOG(stderr, "goldfish-opengl vm ops: set exiting\n"); },
410 .allowRealAudio =
__anon99f56eaf3302() 411 [](bool allow) { DEBUG_LOG(stderr, "goldfish-opengl vm ops: allow real audio\n"); },
412 .physicalMemoryGetAddr =
__anon99f56eaf3402() 413 [](uint64_t gpa) {
414 DEBUG_LOG(stderr, "%s: physmemGetAddr\n", __func__);
415 return (void*)nullptr;
416 },
417 .isRealAudioAllowed =
__anon99f56eaf3502() 418 [](void) {
419 DEBUG_LOG(stderr, "goldfish-opengl vm ops: is real audiop allowed\n");
420 return true;
421 },
422 .setSkipSnapshotSave =
__anon99f56eaf3602() 423 [](bool used) {
424 DEBUG_LOG(stderr, "goldfish-opengl vm ops: set skip snapshot save\n");
425 },
426 .isSnapshotSaveSkipped =
__anon99f56eaf3702() 427 []() {
428 DEBUG_LOG(stderr,
429 "goldfish-opengl vm ops: is snapshot save "
430 "skipped\n");
431 return false;
432 },
433 .hostmemRegister = android_emulation_hostmem_register,
434 .hostmemUnregister = android_emulation_hostmem_unregister,
435 .hostmemGetInfo = android_emulation_hostmem_get_info,
436 #ifdef GFXSTREAM_BUILD_WITH_SNAPSHOT_SUPPORT
437 .setSkipSnapshotSaveReason =
__anon99f56eaf3802() 438 [](SnapshotSkipReason reason) {
439 DEBUG_LOG(stderr,
440 "goldfish-opengl vm ops: set skip snapshot save reason"
441 "skipped\n");
442 },
443 .getSkipSnapshotSaveReason =
__anon99f56eaf3902() 444 []() {
445 DEBUG_LOG(stderr,
446 "goldfish-opengl vm ops: get skip snapshot save "
447 "reason\n");
448 return SNAPSHOT_SKIP_UNKNOWN;
449 },
450 .setStatSnapshotUseVulkan =
__anon99f56eaf3a02() 451 []() {
452 DEBUG_LOG(stderr,
453 "goldfish-opengl vm ops: set stat snapshot use Vulkan"
454 "skipped\n");
455 },
456 .snapshotUseVulkan =
__anon99f56eaf3b02() 457 []() {
458 DEBUG_LOG(stderr,
459 "goldfish-opengl vm ops: get stat snapshot use Vulkan"
460 "skipped\n");
461 return false;
462 },
463 #endif
464 };
465
466 namespace android {
467 namespace emulation {
468
469 const QAndroidVmOperations* const
android_get_QAndroidVmOperations() const470 GfxStreamGraphicsAgentFactory::android_get_QAndroidVmOperations() const {
471 return &sQAndroidVmOperations;
472 }
473
474 const QAndroidMultiDisplayAgent* const
android_get_QAndroidMultiDisplayAgent() const475 GfxStreamGraphicsAgentFactory::android_get_QAndroidMultiDisplayAgent() const {
476 return &sMultiDisplayAgent;
477 }
478
479 const QAndroidEmulatorWindowAgent* const
android_get_QAndroidEmulatorWindowAgent() const480 GfxStreamGraphicsAgentFactory::android_get_QAndroidEmulatorWindowAgent()
481 const {
482 return &sQAndroidEmulatorWindowAgent;
483 }
484 } // namespace emulation
485 } // namespace android
486