// Copyright (C) 2020 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "GfxStreamAgents.h" #include // for uint32_t #include // for fprintf #include // for map, __ma... #include // for pair #include "host-common/HostmemIdMapping.h" // for android_e... #include "host-common/MultiDisplay.h" // for MultiDisp... #include "host-common/multi_display_agent.h" // for QAndroidM... #include "host-common/vm_operations.h" // for SnapshotC... #include "host-common/window_agent.h" // for WindowMes... #include "host-common/misc.h" #ifdef _DEBUG #define DEBUG_LOG(fd, fmt, ...) fprintf(fd, fmt, __VA_ARGS__); #else #define DEBUG_LOG(fd, fmt, ...) #endif static std::map mMultiDisplay; using namespace android; static const QAndroidMultiDisplayAgent sMultiDisplayAgent = { .setMultiDisplay = [](uint32_t id, int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t dpi, uint32_t flag, bool add) -> int { return 0; }, .getMultiDisplay = [](uint32_t id, int32_t* x, int32_t* y, uint32_t* w, uint32_t* h, uint32_t* dpi, uint32_t* flag, bool* enabled) -> bool { if (mMultiDisplay.find(id) == mMultiDisplay.end()) { if (enabled) { *enabled = false; } return false; } if (x) { *x = mMultiDisplay[id].pos_x; } if (y) { *y = mMultiDisplay[id].pos_y; } if (w) { *w = mMultiDisplay[id].width; } if (h) { *h = mMultiDisplay[id].height; } if (dpi) { *dpi = mMultiDisplay[id].dpi; } if (flag) { *flag = mMultiDisplay[id].flag; } if (enabled) { *enabled = mMultiDisplay[id].enabled; } return true; }, .getNextMultiDisplay = [](int32_t start_id, uint32_t* id, int32_t* x, int32_t* y, uint32_t* w, uint32_t* h, uint32_t* dpi, uint32_t* flag, uint32_t* cb) -> bool { uint32_t key; std::map::iterator i; if (start_id < 0) { key = 0; } else { key = start_id + 1; } i = mMultiDisplay.lower_bound(key); if (i == mMultiDisplay.end()) { return false; } else { if (id) { *id = i->first; } if (x) { *x = i->second.pos_x; } if (y) { *y = i->second.pos_y; } if (w) { *w = i->second.width; } if (h) { *h = i->second.height; } if (dpi) { *dpi = i->second.dpi; } if (flag) { *flag = i->second.flag; } if (cb) { *cb = i->second.cb; } return true; } }, .isMultiDisplayEnabled = [](void) -> bool { return mMultiDisplay.size() > 1; }, .getCombinedDisplaySize = [](uint32_t* width, uint32_t* height) {}, .multiDisplayParamValidate = [](uint32_t id, uint32_t w, uint32_t h, uint32_t dpi, uint32_t flag) -> bool { return true; }, .translateCoordination = [](uint32_t* x, uint32_t* y, uint32_t* displayId) -> bool { return true; }, .setGpuMode = [](bool isGuestMode, uint32_t w, uint32_t h) {}, .createDisplay = [](uint32_t* displayId) -> int { if (displayId == nullptr) { fprintf(stderr, "null displayId pointer\n"); return -1; } if (mMultiDisplay.size() >= MultiDisplay::s_maxNumMultiDisplay) { fprintf(stderr, "cannot create more displays, exceeding limits %d\n", MultiDisplay::s_maxNumMultiDisplay); return -1; } if (mMultiDisplay.find(*displayId) != mMultiDisplay.end()) { return 0; } // displays created by internal rcCommands if (*displayId == MultiDisplay::s_invalidIdMultiDisplay) { for (int i = MultiDisplay::s_displayIdInternalBegin; i < MultiDisplay::s_maxNumMultiDisplay; i++) { if (mMultiDisplay.find(i) == mMultiDisplay.end()) { *displayId = i; break; } } } if (*displayId == MultiDisplay::s_invalidIdMultiDisplay) { fprintf(stderr, "cannot create more internaldisplays, exceeding limits %d\n", MultiDisplay::s_maxNumMultiDisplay - MultiDisplay::s_displayIdInternalBegin); return -1; } mMultiDisplay.emplace(*displayId, android::MultiDisplayInfo()); return 0; }, .destroyDisplay = [](uint32_t displayId) -> int { mMultiDisplay.erase(displayId); return 0; }, .setDisplayPose = [](uint32_t displayId, int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t dpi) -> int { if (mMultiDisplay.find(displayId) == mMultiDisplay.end()) { fprintf(stderr, "cannot find display %d\n", displayId); return -1; } mMultiDisplay[displayId].pos_x = x; mMultiDisplay[displayId].pos_y = y; mMultiDisplay[displayId].width = w; mMultiDisplay[displayId].height = h; mMultiDisplay[displayId].dpi = dpi; return 0; }, .getDisplayPose = [](uint32_t displayId, int32_t* x, int32_t* y, uint32_t* w, uint32_t* h) -> int { if (mMultiDisplay.find(displayId) == mMultiDisplay.end()) { fprintf(stderr, "cannot find display %d\n", displayId); return -1; } if (x) *x = mMultiDisplay[displayId].pos_x; if (y) *y = mMultiDisplay[displayId].pos_y; if (w) *w = mMultiDisplay[displayId].width; if (h) *h = mMultiDisplay[displayId].height; return 0; }, .getDisplayColorBuffer = [](uint32_t displayId, uint32_t* colorBuffer) -> int { if (mMultiDisplay.find(displayId) == mMultiDisplay.end()) { fprintf(stderr, "cannot find display %d\n", displayId); return -1; } *colorBuffer = mMultiDisplay[displayId].cb; return 0; }, .getColorBufferDisplay = [](uint32_t colorBuffer, uint32_t* displayId) -> int { for (const auto& iter : mMultiDisplay) { if (iter.second.cb == colorBuffer) { *displayId = iter.first; return 0; } } return -1; }, .setDisplayColorBuffer = [](uint32_t displayId, uint32_t colorBuffer) -> int { if (mMultiDisplay.find(displayId) == mMultiDisplay.end()) { fprintf(stderr, "cannot find display %d\n", displayId); return -1; } mMultiDisplay[displayId].cb = colorBuffer; return 0; }, .isPixelFold = [] () { return false; }, }; static bool sIsFolded = false; static const QAndroidEmulatorWindowAgent sQAndroidEmulatorWindowAgent = { .getEmulatorWindow = [](void) { DEBUG_LOG(stderr, "window-agent-GfxStream-impl: " ".getEmulatorWindow\n"); return (EmulatorWindow*)nullptr; }, .rotate90Clockwise = [](void) { DEBUG_LOG(stderr, "window-agent-GfxStream-impl: " ".rotate90Clockwise\n"); return true; }, .rotate = [](int rotation) { DEBUG_LOG(stderr, "window-agent-GfxStream-impl: " ".rotate90Clockwise\n"); return true; }, .getRotation = [](void) { DEBUG_LOG(stderr, "window-agent-GfxStream-impl: .getRotation\n"); return (int)SKIN_ROTATION_0; }, .showMessage = [](const char* message, WindowMessageType type, int timeoutMs) { DEBUG_LOG(stderr, "window-agent-GfxStream-impl: .showMessage %s\n", message); }, .showMessageWithDismissCallback = [](const char* message, WindowMessageType type, const char* dismissText, void* context, void (*func)(void*), int timeoutMs) { DEBUG_LOG(stderr, "window-agent-GfxStream-impl: " ".showMessageWithDismissCallback %s\n", message); }, .fold = [](bool is_fold) -> bool { DEBUG_LOG(stderr, "window-agent-GfxStream-impl: .fold %d\n", is_fold); sIsFolded = is_fold; return true; }, .isFolded = [](void) -> bool { return sIsFolded; }, .getFoldedArea = [](int* x, int* y, int* w, int* h) -> bool { DEBUG_LOG(stderr, "window-agent-GfxStream-impl: .getFoldedArea\n"); return true; }, .updateFoldablePostureIndicator = [](bool) { DEBUG_LOG(stderr, "window-agent-GfxStream-impl: updateFoldablePostureIndicator\n"); }, .setUIDisplayRegion = [](int x_offset, int y_offset, int w, int h, bool ignoreOrientation) { DEBUG_LOG(stderr, "window-agent-GfxStream-impl: .setUIDisplayRegion " "%d %d %dx%d\n", x_offset, y_offset, w, h); }, .getMultiDisplay = 0, .setNoSkin = [](void) {}, .restoreSkin = [](void) {}, .updateUIMultiDisplayPage = [](uint32_t id) { DEBUG_LOG(stderr, "updateMultiDisplayPage\n"); }, .getMonitorRect = [](uint32_t* w, uint32_t* h) -> bool { if (w) *w = 2500; if (h) *h = 1600; return true; }, }; static const QAndroidVmOperations sQAndroidVmOperations = { .vmStop = []() -> bool { DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm stop\n"); return true; }, .vmStart = []() -> bool { DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm start\n"); return true; }, .vmReset = []() { DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm reset\n"); }, .vmShutdown = []() { DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm reset\n"); }, .vmPause = []() -> bool { DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm pause\n"); return true; }, .vmResume = []() -> bool { DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm resume\n"); return true; }, .vmIsRunning = []() -> bool { DEBUG_LOG(stderr, "goldfish-opengl vm ops: vm is running\n"); return true; }, .snapshotList = [](void*, LineConsumerCallback, LineConsumerCallback) -> bool { DEBUG_LOG(stderr, "goldfish-opengl vm ops: snapshot list\n"); return true; }, .snapshotSave = [](const char* name, void* opaque, LineConsumerCallback) -> bool { DEBUG_LOG(stderr, "gfxstream vm ops: snapshot save\n"); return true; }, .snapshotLoad = [](const char* name, void* opaque, LineConsumerCallback) -> bool { DEBUG_LOG(stderr, "gfxstream vm ops: snapshot load\n"); return true; }, .snapshotDelete = [](const char* name, void* opaque, LineConsumerCallback errConsumer) -> bool { DEBUG_LOG(stderr, "goldfish-opengl vm ops: snapshot delete\n"); return true; }, .snapshotRemap = [](bool shared, void* opaque, LineConsumerCallback errConsumer) -> bool { DEBUG_LOG(stderr, "goldfish-opengl vm ops: snapshot remap\n"); return true; }, .snapshotExport = [](const char* snapshot, const char* dest, void* opaque, LineConsumerCallback errConsumer) -> bool { DEBUG_LOG(stderr, "goldfish-opengl vm ops: snapshot export image\n"); return true; }, .setSnapshotCallbacks = [](void* opaque, const SnapshotCallbacks* callbacks) { DEBUG_LOG(stderr, "goldfish-opengl vm ops: set snapshot callbacks\n"); }, .mapUserBackedRam = [](uint64_t gpa, void* hva, uint64_t size) { DEBUG_LOG(stderr, "%s: map user backed ram\n", __func__); }, .unmapUserBackedRam = [](uint64_t gpa, uint64_t size) { DEBUG_LOG(stderr, "%s: unmap user backed ram\n", __func__); }, .getVmConfiguration = [](VmConfiguration* out) { DEBUG_LOG(stderr, "goldfish-opengl vm ops: get vm configuration\n"); }, .setFailureReason = [](const char* name, int failureReason) { DEBUG_LOG(stderr, "goldfish-opengl vm ops: set failure reason\n"); }, .setExiting = []() { DEBUG_LOG(stderr, "goldfish-opengl vm ops: set exiting\n"); }, .allowRealAudio = [](bool allow) { DEBUG_LOG(stderr, "goldfish-opengl vm ops: allow real audio\n"); }, .physicalMemoryGetAddr = [](uint64_t gpa) { DEBUG_LOG(stderr, "%s: physmemGetAddr\n", __func__); return (void*)nullptr; }, .isRealAudioAllowed = [](void) { DEBUG_LOG(stderr, "goldfish-opengl vm ops: is real audiop allowed\n"); return true; }, .setSkipSnapshotSave = [](bool used) { DEBUG_LOG(stderr, "goldfish-opengl vm ops: set skip snapshot save\n"); }, .isSnapshotSaveSkipped = []() { DEBUG_LOG(stderr, "goldfish-opengl vm ops: is snapshot save " "skipped\n"); return false; }, .hostmemRegister = android_emulation_hostmem_register, .hostmemUnregister = android_emulation_hostmem_unregister, .hostmemGetInfo = android_emulation_hostmem_get_info, }; namespace android { namespace emulation { const QAndroidVmOperations* const GfxStreamGraphicsAgentFactory::android_get_QAndroidVmOperations() const { return &sQAndroidVmOperations; } const QAndroidMultiDisplayAgent* const GfxStreamGraphicsAgentFactory::android_get_QAndroidMultiDisplayAgent() const { return &sMultiDisplayAgent; } const QAndroidEmulatorWindowAgent* const GfxStreamGraphicsAgentFactory::android_get_QAndroidEmulatorWindowAgent() const { return &sQAndroidEmulatorWindowAgent; } } // namespace emulation } // namespace android