blob: 37d87e2b71a5bd46d4d78bc34b303e29f72c0f8c [file] [log] [blame]
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
4 *
5 * Not a Contribution, Apache license notifications and license are retained
6 * for attribution purposes only.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20#include <fcntl.h>
21#include <errno.h>
22
23#include <cutils/log.h>
24#include <utils/Trace.h>
25#include <overlayWriteback.h>
26#include "hwc_utils.h"
27#include "hwc_fbupdate.h"
28#include "hwc_mdpcomp.h"
29#include "hwc_dump_layers.h"
30#include "hwc_copybit.h"
31#include "hwc_virtual.h"
32
33#define HWCVIRTUAL_LOG 0
34
35using namespace qhwc;
36using namespace overlay;
37
38HWCVirtualBase* HWCVirtualBase::getObject() {
39 char property[PROPERTY_VALUE_MAX];
40
41 if((property_get("persist.hwc.enable_vds", property, NULL) > 0)) {
42 if(atoi(property) != 0) {
43 ALOGD_IF(HWCVIRTUAL_LOG, "%s: VDS is enabled for Virtual display",
44 __FUNCTION__);
45 return new HWCVirtualVDS();
46 }
47 }
48 ALOGD_IF(HWCVIRTUAL_LOG, "%s: V4L2 is enabled for Virtual display",
49 __FUNCTION__);
50 return new HWCVirtualV4L2();
51}
52
53void HWCVirtualVDS::init(hwc_context_t *ctx) {
54 const int dpy = HWC_DISPLAY_VIRTUAL;
55 ctx->mFBUpdate[dpy] =
56 IFBUpdate::getObject(ctx, dpy);
57 ctx->mMDPComp[dpy] = MDPComp::getObject(ctx, dpy);
58
59 if(ctx->mFBUpdate[dpy])
60 ctx->mFBUpdate[dpy]->reset();
61 if(ctx->mMDPComp[dpy])
62 ctx->mMDPComp[dpy]->reset();
63}
64
Arun Kumar K.R2aa44c62014-01-21 23:08:28 -080065void HWCVirtualVDS::destroy(hwc_context_t *ctx, size_t /*numDisplays*/,
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080066 hwc_display_contents_1_t** displays) {
67 int dpy = HWC_DISPLAY_VIRTUAL;
68
69 //Cleanup virtual display objs, since there is no explicit disconnect
Raj Kamal52b4fdb2014-01-27 19:35:13 +053070 if(ctx->dpyAttr[dpy].connected && (displays[dpy] == NULL)) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080071 ctx->dpyAttr[dpy].connected = false;
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -080072 ctx->dpyAttr[dpy].isPause = false;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080073
74 if(ctx->mFBUpdate[dpy]) {
75 delete ctx->mFBUpdate[dpy];
76 ctx->mFBUpdate[dpy] = NULL;
77 }
78 if(ctx->mMDPComp[dpy]) {
79 delete ctx->mMDPComp[dpy];
80 ctx->mMDPComp[dpy] = NULL;
81 }
Tatenda Chipeperekwa92961f82014-01-17 13:04:28 -080082 // We reset the WB session to non-secure when the virtual display
83 // has been disconnected.
84 if(!Writeback::getInstance()->setSecure(false)) {
85 ALOGE("Failure while attempting to reset WB session.");
86 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080087 }
88}
89
90int HWCVirtualVDS::prepare(hwc_composer_device_1 *dev,
91 hwc_display_contents_1_t *list) {
92 ATRACE_CALL();
93 //XXX: Fix when framework support is added
94 hwc_context_t* ctx = (hwc_context_t*)(dev);
95 const int dpy = HWC_DISPLAY_VIRTUAL;
96
Tatenda Chipeperekwab0a9f9d2014-01-20 09:23:21 -080097 if (list && list->outbuf && list->numHwLayers > 0) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080098 reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
99 uint32_t last = list->numHwLayers - 1;
100 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
101 int fbWidth = 0, fbHeight = 0;
102 getLayerResolution(fbLayer, fbWidth, fbHeight);
103 ctx->dpyAttr[dpy].xres = fbWidth;
104 ctx->dpyAttr[dpy].yres = fbHeight;
105
106 if(ctx->dpyAttr[dpy].connected == false) {
107 ctx->dpyAttr[dpy].connected = true;
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800108 ctx->dpyAttr[dpy].isPause = false;
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800109 // We set the vsync period to the primary refresh rate, leaving
110 // it up to the consumer to decide how fast to consume frames.
111 ctx->dpyAttr[dpy].vsync_period
112 = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800113 init(ctx);
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800114 // XXX: for architectures with limited resources we would normally
115 // allow one padding round to free up resources but this breaks
116 // certain use cases.
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800117 }
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800118 if(!ctx->dpyAttr[dpy].isPause) {
119 ctx->dpyAttr[dpy].isConfiguring = false;
120 ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
121 private_handle_t *ohnd = (private_handle_t *)list->outbuf;
122 Writeback::getInstance()->configureDpyInfo(ohnd->width,
123 ohnd->height);
124 setListStats(ctx, list, dpy);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800125
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800126 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
127 const int fbZ = 0;
128 ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
129 }
130 } else {
131 /* Virtual Display is in Pause state.
132 * Mark all application layers as OVERLAY so that
133 * GPU will not compose.
134 */
135 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
136 hwc_layer_1_t *layer = &list->hwLayers[i];
137 layer->compositionType = HWC_OVERLAY;
138 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800139 }
140 }
141 return 0;
142}
143
144int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
145 ATRACE_CALL();
146 int ret = 0;
147 const int dpy = HWC_DISPLAY_VIRTUAL;
148
Tatenda Chipeperekwaf19f84d2014-01-17 12:43:29 -0800149 if (list && list->outbuf && list->numHwLayers > 0) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800150 uint32_t last = list->numHwLayers - 1;
151 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
152
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800153 if(ctx->dpyAttr[dpy].connected
154 && (!ctx->dpyAttr[dpy].isPause))
155 {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800156 private_handle_t *ohnd = (private_handle_t *)list->outbuf;
Tatenda Chipeperekwaa2fdebe2014-01-20 12:29:50 -0800157 int format = ohnd->format;
158 if (format == HAL_PIXEL_FORMAT_RGBA_8888)
159 format = HAL_PIXEL_FORMAT_RGBX_8888;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800160 Writeback::getInstance()->setOutputFormat(
Tatenda Chipeperekwaa2fdebe2014-01-20 12:29:50 -0800161 utils::getMdpFormat(format));
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800162
Tatenda Chipeperekwa92961f82014-01-17 13:04:28 -0800163 // Configure WB as secure if the output buffer handle is secure.
164 if(isSecureBuffer(ohnd)){
165 if(! Writeback::getInstance()->setSecure(true))
166 {
167 ALOGE("Failed to set WB as secure for virtual display");
168 return false;
169 }
170 }
171
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800172 int fd = -1; //FenceFD from the Copybit
173 hwc_sync(ctx, list, dpy, fd);
174
175 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
176 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
177 ret = -1;
178 }
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800179 // We need an FB layer handle check to cater for this usecase:
180 // Video is playing in landscape on primary, then launch
181 // ScreenRecord app.
182 // In this scenario, the first VDS draw call will have HWC
183 // composition and VDS does nit involve GPU to get eglSwapBuffer
184 // to get valid fb handle.
185 if (fbLayer->handle && !ctx->mFBUpdate[dpy]->draw(ctx,
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800186 (private_handle_t *)fbLayer->handle)) {
187 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
188 ret = -1;
189 }
190
191 Writeback::getInstance()->queueBuffer(ohnd->fd, ohnd->offset);
192 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
193 ALOGE("%s: display commit fail!", __FUNCTION__);
194 ret = -1;
195 }
196
197 } else if(list->outbufAcquireFenceFd >= 0) {
198 //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
199 //which will make sure, the framework waits on it and closes it.
200 //The other way is to wait on outbufFenceFd ourselves, close it and
201 //set retireFenceFd to -1. Since we want hwc to be async, choosing
202 //the former.
203 //Also dup because, the closeAcquireFds() will close the outbufFence
204 list->retireFenceFd = dup(list->outbufAcquireFenceFd);
205 }
206 }
207
208 closeAcquireFds(list);
209 return ret;
210}
211
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800212void HWCVirtualVDS::pause(hwc_context_t* ctx, int dpy) {
213 {
214 Locker::Autolock _l(ctx->mDrawLock);
215 ctx->dpyAttr[dpy].isActive = true;
216 ctx->dpyAttr[dpy].isPause = true;
217 ctx->proc->invalidate(ctx->proc);
218 }
219 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
220 * 2 / 1000);
221 return;
222}
223
224void HWCVirtualVDS::resume(hwc_context_t* ctx, int dpy) {
225 {
226 Locker::Autolock _l(ctx->mDrawLock);
227 ctx->dpyAttr[dpy].isConfiguring = true;
228 ctx->dpyAttr[dpy].isActive = true;
229 ctx->proc->invalidate(ctx->proc);
230 }
231 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
232 * 2 / 1000);
233 //At this point external has all the pipes it would need.
234 {
235 Locker::Autolock _l(ctx->mDrawLock);
236 ctx->dpyAttr[dpy].isPause = false;
237 ctx->proc->invalidate(ctx->proc);
238 }
239 return;
240}
241
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800242/* Implementation for HWCVirtualV4L2 class */
243
244int HWCVirtualV4L2::prepare(hwc_composer_device_1 *dev,
245 hwc_display_contents_1_t *list) {
246 ATRACE_CALL();
247
248 hwc_context_t* ctx = (hwc_context_t*)(dev);
249 const int dpy = HWC_DISPLAY_VIRTUAL;
250
251 if (LIKELY(list && list->numHwLayers > 1) &&
252 ctx->dpyAttr[dpy].isActive &&
Raj Kamal52b4fdb2014-01-27 19:35:13 +0530253 ctx->dpyAttr[dpy].connected &&
254 canUseMDPforVirtualDisplay(ctx,list)) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800255 reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
256 if(!ctx->dpyAttr[dpy].isPause) {
257 ctx->dpyAttr[dpy].isConfiguring = false;
258 setListStats(ctx, list, dpy);
259 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
260 const int fbZ = 0;
Manoj Kumar AVM0901c042014-02-10 20:06:08 -0800261 ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800262 }
263 } else {
264 /* Virtual Display is in Pause state.
265 * Mark all application layers as OVERLAY so that
266 * GPU will not compose.
267 */
268 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
269 hwc_layer_1_t *layer = &list->hwLayers[i];
270 layer->compositionType = HWC_OVERLAY;
271 }
272 }
273 }
274 return 0;
275}
276
277int HWCVirtualV4L2::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
278 ATRACE_CALL();
279 int ret = 0;
280
281 const int dpy = HWC_DISPLAY_VIRTUAL;
282
283 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
284 ctx->dpyAttr[dpy].connected &&
Raj Kamal52b4fdb2014-01-27 19:35:13 +0530285 (!ctx->dpyAttr[dpy].isPause) &&
286 canUseMDPforVirtualDisplay(ctx,list)) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800287 uint32_t last = list->numHwLayers - 1;
288 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
289 int fd = -1; //FenceFD from the Copybit(valid in async mode)
290 bool copybitDone = false;
291 if(ctx->mCopyBit[dpy])
292 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
293
294 if(list->numHwLayers > 1)
295 hwc_sync(ctx, list, dpy, fd);
296
297 // Dump the layers for virtual
298 if(ctx->mHwcDebug[dpy])
299 ctx->mHwcDebug[dpy]->dumpLayers(list);
300
301 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
302 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
303 ret = -1;
304 }
305
306 int extOnlyLayerIndex =
307 ctx->listStats[dpy].extOnlyLayerIndex;
308
309 private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
310 if(extOnlyLayerIndex!= -1) {
311 hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
312 hnd = (private_handle_t *)extLayer->handle;
313 } else if(copybitDone) {
314 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
315 }
316
317 if(hnd && !isYuvBuffer(hnd)) {
318 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
319 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
320 ret = -1;
321 }
322 }
323
324 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
325 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
326 ret = -1;
327 }
328 }
329
330 closeAcquireFds(list);
331
Baldev Sahuec852382014-02-14 08:36:00 +0530332 if (list && list->outbuf && (list->retireFenceFd < 0) ) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800333 // SF assumes HWC waits for the acquire fence and returns a new fence
334 // that signals when we're done. Since we don't wait, and also don't
335 // touch the buffer, we can just handle the acquire fence back to SF
336 // as the retire fence.
337 list->retireFenceFd = list->outbufAcquireFenceFd;
338 }
339
340 return ret;
341}
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800342
343void HWCVirtualV4L2::pause(hwc_context_t* ctx, int dpy) {
344 {
345 Locker::Autolock _l(ctx->mDrawLock);
346 ctx->dpyAttr[dpy].isActive = true;
347 ctx->dpyAttr[dpy].isPause = true;
348 ctx->proc->invalidate(ctx->proc);
349 }
350 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
351 * 2 / 1000);
352 // At this point all the pipes used by External have been
353 // marked as UNSET.
354 {
355 Locker::Autolock _l(ctx->mDrawLock);
356 // Perform commit to unstage the pipes.
357 if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
358 ALOGE("%s: display commit fail! for %d dpy",
359 __FUNCTION__, dpy);
360 }
361 }
362 return;
363}
364
365void HWCVirtualV4L2::resume(hwc_context_t* ctx, int dpy){
366 //Treat Resume as Online event
367 //Since external didnt have any pipes, force primary to give up
368 //its pipes; we don't allow inter-mixer pipe transfers.
369 {
370 Locker::Autolock _l(ctx->mDrawLock);
371
372 // A dynamic resolution change (DRC) can be made for a WiFi
373 // display. In order to support the resolution change, we
374 // need to reconfigure the corresponding display attributes.
375 // Since DRC is only on WiFi display, we only need to call
376 // configure() on the VirtualDisplay device.
377 //TODO: clean up
378 if(dpy == HWC_DISPLAY_VIRTUAL)
379 ctx->mVirtualDisplay->configure();
380
381 ctx->dpyAttr[dpy].isConfiguring = true;
382 ctx->dpyAttr[dpy].isActive = true;
383 ctx->proc->invalidate(ctx->proc);
384 }
385 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
386 * 2 / 1000);
387 //At this point external has all the pipes it would need.
388 {
389 Locker::Autolock _l(ctx->mDrawLock);
390 ctx->dpyAttr[dpy].isPause = false;
391 ctx->proc->invalidate(ctx->proc);
392 }
393 return;
394}