blob: 27cc00e195880173d797f3397d8b63648be92ba9 [file] [log] [blame]
Steve Kondik55db0532017-06-12 11:27:18 -07001/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "VNC-VirtualDisplay"
18//#define LOG_NDEBUG 0
19#include <utils/Log.h>
20
21#include <binder/IPCThreadState.h>
22#include <binder/ProcessState.h>
23
24#include <gui/SurfaceComposerClient.h>
25
Steve Kondik55db0532017-06-12 11:27:18 -070026#include <GLES3/gl3.h>
Steve Kondikdda11002017-06-13 08:20:27 -070027#include <GLES3/gl3ext.h>
28#include <GLES2/gl2ext.h>
Steve Kondik55db0532017-06-12 11:27:18 -070029
30#include <ui/Rect.h>
31
32#include "VirtualDisplay.h"
33
34using namespace android;
35
36static const int kGlBytesPerPixel = 4; // GL_RGBA
37
38
39/*
40 * Returns "true" if the device is rotated 90 degrees.
41 */
42bool VirtualDisplay::isDeviceRotated(int orientation) {
43 return orientation != DISPLAY_ORIENTATION_0 &&
44 orientation != DISPLAY_ORIENTATION_180;
45}
46
47/*
48 * Sets the display projection, based on the display dimensions, video size,
49 * and device orientation.
50 */
51status_t VirtualDisplay::setDisplayProjection(const sp<IBinder>& dpy,
52 const DisplayInfo& mMainDpyInfo) {
53 status_t err;
54
55 // Set the region of the layer stack we're interested in, which in our
56 // case is "all of it". If the app is rotated (so that the width of the
57 // app is based on the height of the display), reverse width/height.
58 bool deviceRotated = isDeviceRotated(mMainDpyInfo.orientation);
59 uint32_t sourceWidth, sourceHeight;
60 if (!deviceRotated) {
61 sourceWidth = mMainDpyInfo.w;
62 sourceHeight = mMainDpyInfo.h;
63 } else {
64 ALOGV("using rotated width/height");
65 sourceHeight = mMainDpyInfo.w;
66 sourceWidth = mMainDpyInfo.h;
67 }
68 Rect layerStackRect(sourceWidth, sourceHeight);
69
70 // We need to preserve the aspect ratio of the display.
71 float displayAspect = (float) sourceHeight / (float) sourceWidth;
72
73
74 // Set the way we map the output onto the display surface (which will
75 // be e.g. 1280x720 for a 720p video). The rect is interpreted
76 // post-rotation, so if the display is rotated 90 degrees we need to
77 // "pre-rotate" it by flipping width/height, so that the orientation
78 // adjustment changes it back.
79 //
80 // We might want to encode a portrait display as landscape to use more
81 // of the screen real estate. (If players respect a 90-degree rotation
82 // hint, we can essentially get a 720x1280 video instead of 1280x720.)
83 // In that case, we swap the configured video width/height and then
84 // supply a rotation value to the display projection.
85 uint32_t videoWidth, videoHeight;
86 uint32_t outWidth, outHeight;
87 if (!mRotate) {
88 videoWidth = mWidth;
89 videoHeight = mHeight;
90 } else {
91 videoWidth = mHeight;
92 videoHeight = mWidth;
93 }
94 if (videoHeight > (uint32_t)(videoWidth * displayAspect)) {
95 // limited by narrow width; reduce height
96 outWidth = videoWidth;
97 outHeight = (uint32_t)(videoWidth * displayAspect);
98 } else {
99 // limited by short height; restrict width
100 outHeight = videoHeight;
101 outWidth = (uint32_t)(videoHeight / displayAspect);
102 }
103 uint32_t offX, offY;
104 offX = (videoWidth - outWidth) / 2;
105 offY = (videoHeight - outHeight) / 2;
106 Rect displayRect(offX, offY, offX + outWidth, offY + outHeight);
107
108 if (mRotate) {
Steve Kondikef4e8652017-06-14 15:07:54 -0700109 ALOGV("Rotated content area is %ux%u at offset x=%d y=%d\n",
Steve Kondik55db0532017-06-12 11:27:18 -0700110 outHeight, outWidth, offY, offX);
111 } else {
Steve Kondikef4e8652017-06-14 15:07:54 -0700112 ALOGV("Content area is %ux%u at offset x=%d y=%d\n",
Steve Kondik55db0532017-06-12 11:27:18 -0700113 outWidth, outHeight, offX, offY);
114 }
115
116 SurfaceComposerClient::setDisplayProjection(dpy,
117 mRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0,
118 layerStackRect, displayRect);
119 return NO_ERROR;
120}
121
Steve Kondik7225c7f2017-06-14 00:06:16 -0700122status_t VirtualDisplay::start(const DisplayInfo& mainDpyInfo) {
Steve Kondik55db0532017-06-12 11:27:18 -0700123
124 Mutex::Autolock _l(mMutex);
125
Steve Kondikef4e8652017-06-14 15:07:54 -0700126 ALOGV("Orientation: %d", mainDpyInfo.orientation);
Steve Kondik55db0532017-06-12 11:27:18 -0700127 mRotate = isDeviceRotated(mainDpyInfo.orientation);
128 mWidth = mRotate ? mainDpyInfo.h : mainDpyInfo.w;
129 mHeight = mRotate ? mainDpyInfo.w : mainDpyInfo.h;
130
131 sp<ProcessState> self = ProcessState::self();
132 self->startThreadPool();
133
134 run("vnc-virtualdisplay");
135
136 mState = INIT;
137 while (mState == INIT) {
138 mStartCond.wait(mMutex);
139 }
140
141 if (mThreadResult != NO_ERROR) {
142 ALOGE("Failed to start VDS thread: err=%d", mThreadResult);
143 return mThreadResult;
144 }
145 assert(mState == RUNNING);
146
147 mDpy = SurfaceComposerClient::createDisplay(
148 String8("VNCFlinger"), false /*secure*/);
149
150 SurfaceComposerClient::openGlobalTransaction();
151 SurfaceComposerClient::setDisplaySurface(mDpy, mProducer);
152 setDisplayProjection(mDpy, mainDpyInfo);
153 SurfaceComposerClient::setDisplayLayerStack(mDpy, 0); // default stack
154 SurfaceComposerClient::closeGlobalTransaction();
155
156 ALOGV("VirtualDisplay::start successful");
157 return NO_ERROR;
158}
159
160status_t VirtualDisplay::stop() {
161 Mutex::Autolock _l(mMutex);
162 mState = STOPPING;
163 mEventCond.signal();
164 return NO_ERROR;
165}
166
167bool VirtualDisplay::threadLoop() {
168 Mutex::Autolock _l(mMutex);
169
170 mThreadResult = setup_l();
171
172 if (mThreadResult != NO_ERROR) {
173 ALOGW("Aborting VDS thread");
174 mState = STOPPED;
175 release_l();
176 mStartCond.broadcast();
177 return false;
178 }
179
180 ALOGV("VDS thread running");
181 mState = RUNNING;
182 mStartCond.broadcast();
183
184 while (mState == RUNNING) {
185 mEventCond.wait(mMutex);
186 ALOGD("Awake, frame available");
Steve Kondik7225c7f2017-06-14 00:06:16 -0700187 processFrame_l();
Steve Kondik55db0532017-06-12 11:27:18 -0700188 }
189
190 ALOGV("VDS thread stopping");
191 release_l();
192 mState = STOPPED;
193 return false; // stop
194}
195
196status_t VirtualDisplay::setup_l() {
197 status_t err;
198
Steve Kondik55db0532017-06-12 11:27:18 -0700199 sp<IGraphicBufferConsumer> consumer;
200 BufferQueue::createBufferQueue(&mProducer, &consumer);
Steve Kondikef4e8652017-06-14 15:07:54 -0700201 mCpuConsumer = new CpuConsumer(consumer, 1);
202 mCpuConsumer->setName(String8("vds-to-cpu"));
203 mCpuConsumer->setDefaultBufferSize(mWidth, mHeight);
Steve Kondik55db0532017-06-12 11:27:18 -0700204 mProducer->setMaxDequeuedBufferCount(4);
Steve Kondik55db0532017-06-12 11:27:18 -0700205
Steve Kondikef4e8652017-06-14 15:07:54 -0700206 mCpuConsumer->setFrameAvailableListener(this);
Steve Kondik55db0532017-06-12 11:27:18 -0700207
208 ALOGD("VirtualDisplay::setup_l OK");
209 return NO_ERROR;
210}
211
212void* VirtualDisplay::processFrame_l() {
213 ALOGD("processFrame_l\n");
214
Steve Kondikef4e8652017-06-14 15:07:54 -0700215 mUpdateMutex->lock();
Steve Kondik55db0532017-06-12 11:27:18 -0700216
Steve Kondikef4e8652017-06-14 15:07:54 -0700217 CpuConsumer::LockedBuffer imgBuffer;
218 status_t res = mCpuConsumer->lockNextBuffer(&imgBuffer);
219 if (res != OK) {
220 ALOGE("Failed to lock next buffer: %s (%d)", strerror(-res), res);
221 return nullptr;
Steve Kondik55db0532017-06-12 11:27:18 -0700222 }
223
Steve Kondikef4e8652017-06-14 15:07:54 -0700224 ALOGV("imgBuffer ptr: %p format: %x (%dx%d, stride=%d)", imgBuffer.data, imgBuffer.format, imgBuffer.width, imgBuffer.height, imgBuffer.stride);
Steve Kondikdda11002017-06-13 08:20:27 -0700225
Steve Kondikef4e8652017-06-14 15:07:54 -0700226 void* vncbuf = mVNCScreen->frameBuffer;
227 void* imgbuf = imgBuffer.data;
228
229 for (size_t y = 0; y < mHeight; y++) {
230 memcpy(vncbuf, imgbuf, mWidth * 4);
231 vncbuf = (void *)((char *)vncbuf + mWidth * 4);
232 imgbuf = (void *)((char *)imgbuf + imgBuffer.stride * 4);
233 }
234 ALOGD("buf copied");
235
236 mVNCScreen->frameBuffer = (char *)imgBuffer.data;
237 mVNCScreen->paddedWidthInBytes = imgBuffer.stride * 4;
Steve Kondikdda11002017-06-13 08:20:27 -0700238 rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
Steve Kondikdda11002017-06-13 08:20:27 -0700239
Steve Kondik55db0532017-06-12 11:27:18 -0700240
Steve Kondikef4e8652017-06-14 15:07:54 -0700241 mCpuConsumer->unlockBuffer(imgBuffer);
242 mUpdateMutex->unlock();
Steve Kondikdda11002017-06-13 08:20:27 -0700243
Steve Kondikef4e8652017-06-14 15:07:54 -0700244 return nullptr;
Steve Kondik55db0532017-06-12 11:27:18 -0700245}
246
247void VirtualDisplay::release_l() {
248 ALOGD("release_l");
Steve Kondikef4e8652017-06-14 15:07:54 -0700249 mCpuConsumer.clear();
Steve Kondik55db0532017-06-12 11:27:18 -0700250 mProducer.clear();
Steve Kondik55db0532017-06-12 11:27:18 -0700251 SurfaceComposerClient::destroyDisplay(mDpy);
252}
253
254// Callback; executes on arbitrary thread.
255void VirtualDisplay::onFrameAvailable(const BufferItem& item) {
256 Mutex::Autolock _l(mMutex);
257 mEventCond.signal();
258 ALOGD("mTimestamp=%ld mFrameNumber=%ld", item.mTimestamp, item.mFrameNumber);
259}