blob: 72c58965e7a3484b334733dd0f9f1e135095a563 [file] [log] [blame]
Steve Kondik961b4cc2017-06-22 18:10:50 -07001#define LOG_TAG "AndroidDesktop"
2#include <utils/Log.h>
3
4#include <fcntl.h>
5#include <sys/eventfd.h>
6
Steve Kondik961b4cc2017-06-22 18:10:50 -07007#include <gui/ISurfaceComposer.h>
8#include <gui/SurfaceComposerClient.h>
9
10#include <ui/DisplayInfo.h>
11
12#include <rfb/PixelFormat.h>
13#include <rfb/Rect.h>
14#include <rfb/ScreenSet.h>
15#include <rfb/VNCServerST.h>
16
17#include "AndroidDesktop.h"
Steve Kondik6f9ab852017-07-09 21:30:20 -070018#include "AndroidPixelBuffer.h"
Steve Kondik961b4cc2017-06-22 18:10:50 -070019#include "InputDevice.h"
Steve Kondik6f9ab852017-07-09 21:30:20 -070020#include "VirtualDisplay.h"
Steve Kondik961b4cc2017-06-22 18:10:50 -070021
22using namespace vncflinger;
23using namespace android;
24
Steve Kondik961b4cc2017-06-22 18:10:50 -070025AndroidDesktop::AndroidDesktop() {
Steve Kondik961b4cc2017-06-22 18:10:50 -070026 mInputDevice = new InputDevice();
Steve Kondik6f9ab852017-07-09 21:30:20 -070027 mDisplayRect = Rect(0, 0);
Steve Kondik961b4cc2017-06-22 18:10:50 -070028
29 mEventFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
30 if (mEventFd < 0) {
31 ALOGE("Failed to create event notifier");
32 return;
33 }
34}
35
36AndroidDesktop::~AndroidDesktop() {
37 mInputDevice->stop();
38 close(mEventFd);
39}
40
41void AndroidDesktop::start(rfb::VNCServer* vs) {
Steve Kondik961b4cc2017-06-22 18:10:50 -070042 mMainDpy = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
Steve Kondik961b4cc2017-06-22 18:10:50 -070043
44 mServer = (rfb::VNCServerST*)vs;
45
Steve Kondik6f9ab852017-07-09 21:30:20 -070046 mPixels = new AndroidPixelBuffer();
47 mPixels->setDimensionsChangedListener(this);
Steve Kondik961b4cc2017-06-22 18:10:50 -070048
Steve Kondik6f9ab852017-07-09 21:30:20 -070049 if (updateDisplayInfo() != NO_ERROR) {
50 ALOGE("Failed to query display!");
51 return;
52 }
Steve Kondik961b4cc2017-06-22 18:10:50 -070053
54 ALOGV("Desktop is running");
55}
56
57void AndroidDesktop::stop() {
Steve Kondik6f9ab852017-07-09 21:30:20 -070058 Mutex::Autolock _L(mLock);
Steve Kondik961b4cc2017-06-22 18:10:50 -070059
60 ALOGV("Shutting down");
61
62 mServer->setPixelBuffer(0);
Steve Kondik961b4cc2017-06-22 18:10:50 -070063
Steve Kondik6f9ab852017-07-09 21:30:20 -070064 mVirtualDisplay.clear();
65 mPixels.clear();
Steve Kondik961b4cc2017-06-22 18:10:50 -070066}
67
68void AndroidDesktop::processFrames() {
Steve Kondik6f9ab852017-07-09 21:30:20 -070069 Mutex::Autolock _l(mLock);
Steve Kondik961b4cc2017-06-22 18:10:50 -070070
Steve Kondik6f9ab852017-07-09 21:30:20 -070071 updateDisplayInfo();
Steve Kondik961b4cc2017-06-22 18:10:50 -070072
73 // get a frame from the virtual display
74 CpuConsumer::LockedBuffer imgBuffer;
Steve Kondik6f9ab852017-07-09 21:30:20 -070075 status_t res = mVirtualDisplay->getConsumer()->lockNextBuffer(&imgBuffer);
Steve Kondik961b4cc2017-06-22 18:10:50 -070076 if (res != OK) {
77 ALOGE("Failed to lock next buffer: %s (%d)", strerror(-res), res);
78 return;
79 }
80
81 mFrameNumber = imgBuffer.frameNumber;
82 ALOGV("processFrame: [%lu] format: %x (%dx%d, stride=%d)", mFrameNumber, imgBuffer.format,
83 imgBuffer.width, imgBuffer.height, imgBuffer.stride);
84
85 // we don't know if there was a stride change until we get
86 // a buffer from the queue. if it changed, we need to resize
87
88 rfb::Rect bufRect(0, 0, imgBuffer.width, imgBuffer.height);
89
90 // performance is extremely bad if the gpu memory is used
91 // directly without copying because it is likely uncached
92 mPixels->imageRect(bufRect, imgBuffer.data, imgBuffer.stride);
93
Steve Kondik6f9ab852017-07-09 21:30:20 -070094 mVirtualDisplay->getConsumer()->unlockBuffer(imgBuffer);
Steve Kondik961b4cc2017-06-22 18:10:50 -070095
96 // update clients
97 mServer->add_changed(bufRect);
Steve Kondik961b4cc2017-06-22 18:10:50 -070098}
99
100// notifies the server loop that we have changes
101void AndroidDesktop::notify() {
102 static uint64_t notify = 1;
103 write(mEventFd, &notify, sizeof(notify));
104}
105
106// called when a client resizes the window
107unsigned int AndroidDesktop::setScreenLayout(int reqWidth, int reqHeight,
108 const rfb::ScreenSet& layout) {
Steve Kondik6f9ab852017-07-09 21:30:20 -0700109 Mutex::Autolock _l(mLock);
Steve Kondik961b4cc2017-06-22 18:10:50 -0700110
111 char* dbg = new char[1024];
112 layout.print(dbg, 1024);
113
Steve Kondik6f9ab852017-07-09 21:30:20 -0700114 ALOGD("setScreenLayout: cur: %s new: %dx%d", dbg, reqWidth, reqHeight);
Steve Kondik961b4cc2017-06-22 18:10:50 -0700115 delete[] dbg;
116
Steve Kondik6f9ab852017-07-09 21:30:20 -0700117 if (reqWidth == mDisplayRect.getWidth() && reqHeight == mDisplayRect.getHeight()) {
Steve Kondik961b4cc2017-06-22 18:10:50 -0700118 return rfb::resultInvalid;
119 }
120
121 if (reqWidth > 0 && reqHeight > 0) {
Steve Kondik6f9ab852017-07-09 21:30:20 -0700122 mPixels->setWindowSize(reqWidth, reqHeight);
Steve Kondik961b4cc2017-06-22 18:10:50 -0700123
Steve Kondik6f9ab852017-07-09 21:30:20 -0700124 rfb::ScreenSet screens;
125 screens.add_screen(rfb::Screen(0, 0, 0, mPixels->width(), mPixels->height(), 0));
126 mServer->setScreenLayout(screens);
127 return rfb::resultSuccess;
Steve Kondik961b4cc2017-06-22 18:10:50 -0700128 }
Steve Kondik6f9ab852017-07-09 21:30:20 -0700129
Steve Kondik961b4cc2017-06-22 18:10:50 -0700130 return rfb::resultInvalid;
131}
132
Steve Kondik961b4cc2017-06-22 18:10:50 -0700133// cpuconsumer frame listener, called from binder thread
Steve Kondik6f9ab852017-07-09 21:30:20 -0700134void AndroidDesktop::onFrameAvailable(const BufferItem& item) {
Steve Kondik961b4cc2017-06-22 18:10:50 -0700135 ALOGV("onFrameAvailable: [%lu] mTimestamp=%ld", item.mFrameNumber, item.mTimestamp);
Steve Kondik6f9ab852017-07-09 21:30:20 -0700136
137 notify();
Steve Kondik961b4cc2017-06-22 18:10:50 -0700138}
139
140rfb::Point AndroidDesktop::getFbSize() {
141 return rfb::Point(mPixels->width(), mPixels->height());
142}
143
144void AndroidDesktop::keyEvent(rdr::U32 key, bool down) {
145 mInputDevice->keyEvent(down, key);
146}
147
148void AndroidDesktop::pointerEvent(const rfb::Point& pos, int buttonMask) {
Steve Kondik6f9ab852017-07-09 21:30:20 -0700149 if (pos.x < mDisplayRect.left || pos.x > mDisplayRect.right || pos.y < mDisplayRect.top ||
150 pos.y > mDisplayRect.bottom) {
Steve Kondik961b4cc2017-06-22 18:10:50 -0700151 // outside viewport
152 return;
153 }
Steve Kondik6f9ab852017-07-09 21:30:20 -0700154 uint32_t x = pos.x * ((float)(mDisplayRect.getWidth()) / (float)mPixels->width());
155 uint32_t y = pos.y * ((float)(mDisplayRect.getHeight()) / (float)mPixels->height());
Steve Kondik961b4cc2017-06-22 18:10:50 -0700156
Steve Kondik6f9ab852017-07-09 21:30:20 -0700157 ALOGV("pointer xlate x1=%d y1=%d x2=%d y2=%d", pos.x, pos.y, x, y);
Steve Kondik961b4cc2017-06-22 18:10:50 -0700158
159 mServer->setCursorPos(rfb::Point(x, y));
160 mInputDevice->pointerEvent(buttonMask, x, y);
161}
162
Steve Kondik6f9ab852017-07-09 21:30:20 -0700163// refresh the display dimensions
164status_t AndroidDesktop::updateDisplayInfo() {
165 status_t err = SurfaceComposerClient::getDisplayInfo(mMainDpy, &mDisplayInfo);
Steve Kondik961b4cc2017-06-22 18:10:50 -0700166 if (err != NO_ERROR) {
167 ALOGE("Failed to get display characteristics\n");
168 return err;
169 }
170
Steve Kondik6f9ab852017-07-09 21:30:20 -0700171 mPixels->setDisplayInfo(&mDisplayInfo);
Steve Kondik961b4cc2017-06-22 18:10:50 -0700172
173 return NO_ERROR;
174}
Steve Kondik6f9ab852017-07-09 21:30:20 -0700175
176void AndroidDesktop::onBufferDimensionsChanged(uint32_t width, uint32_t height) {
177 ALOGV("Dimensions changed: old=(%ux%u) new=(%ux%u)", mDisplayRect.getWidth(),
178 mDisplayRect.getHeight(), width, height);
179
180 mVirtualDisplay.clear();
181 mVirtualDisplay = new VirtualDisplay(&mDisplayInfo, mPixels->width(), mPixels->height(), this);
182
183 mDisplayRect = mVirtualDisplay->getDisplayRect();
184
185 mInputDevice->reconfigure(mDisplayRect.getWidth(), mDisplayRect.getHeight());
186
187 mServer->setPixelBuffer(mPixels.get());
188
189 rfb::ScreenSet screens;
190 screens.add_screen(rfb::Screen(0, 0, 0, mPixels->width(), mPixels->height(), 0));
191 mServer->setScreenLayout(screens);
192}