blob: b65f4177033ec6779f4f241fd87dc04d202a0bac [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"
Tatenda Chipeperekwa523eac52014-05-29 14:58:39 -070032#include "sync/sync.h"
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080033
34#define HWCVIRTUAL_LOG 0
35
36using namespace qhwc;
37using namespace overlay;
38
Tatenda Chipeperekwa06af9cb2014-08-26 14:51:05 -070039bool HWCVirtualBase::sVDDumpEnabled = false;
Raj kamal59fea562014-04-01 16:52:19 +053040HWCVirtualBase* HWCVirtualBase::getObject(bool isVDSEnabled) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080041
Raj kamal59fea562014-04-01 16:52:19 +053042 if(isVDSEnabled) {
43 ALOGD_IF(HWCVIRTUAL_LOG, "%s: VDS is enabled for Virtual display",
44 __FUNCTION__);
45 return new HWCVirtualVDS();
46 } else {
47 ALOGD_IF(HWCVIRTUAL_LOG, "%s: V4L2 is enabled for Virtual display",
48 __FUNCTION__);
49 return new HWCVirtualV4L2();
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080050 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080051}
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 }
Raj kamal59fea562014-04-01 16:52:19 +053087 ctx->mWfdSyncLock.lock();
88 ctx->mWfdSyncLock.signal();
89 ctx->mWfdSyncLock.unlock();
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080090 }
91}
92
93int HWCVirtualVDS::prepare(hwc_composer_device_1 *dev,
94 hwc_display_contents_1_t *list) {
95 ATRACE_CALL();
96 //XXX: Fix when framework support is added
97 hwc_context_t* ctx = (hwc_context_t*)(dev);
98 const int dpy = HWC_DISPLAY_VIRTUAL;
99
Tatenda Chipeperekwab0a9f9d2014-01-20 09:23:21 -0800100 if (list && list->outbuf && list->numHwLayers > 0) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530101 reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
102 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800103 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
104 int fbWidth = 0, fbHeight = 0;
105 getLayerResolution(fbLayer, fbWidth, fbHeight);
106 ctx->dpyAttr[dpy].xres = fbWidth;
107 ctx->dpyAttr[dpy].yres = fbHeight;
108
109 if(ctx->dpyAttr[dpy].connected == false) {
110 ctx->dpyAttr[dpy].connected = true;
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800111 ctx->dpyAttr[dpy].isPause = false;
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800112 // We set the vsync period to the primary refresh rate, leaving
113 // it up to the consumer to decide how fast to consume frames.
114 ctx->dpyAttr[dpy].vsync_period
115 = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800116 init(ctx);
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800117 // XXX: for architectures with limited resources we would normally
118 // allow one padding round to free up resources but this breaks
119 // certain use cases.
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800120 }
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800121 if(!ctx->dpyAttr[dpy].isPause) {
122 ctx->dpyAttr[dpy].isConfiguring = false;
123 ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
124 private_handle_t *ohnd = (private_handle_t *)list->outbuf;
125 Writeback::getInstance()->configureDpyInfo(ohnd->width,
126 ohnd->height);
127 setListStats(ctx, list, dpy);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800128
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800129 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
130 const int fbZ = 0;
Saurabh Shahef19fe32014-04-22 15:31:58 -0700131 if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
132 {
133 ctx->mOverlay->clear(dpy);
134 ctx->mLayerRotMap[dpy]->clear();
135 }
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800136 }
137 } else {
138 /* Virtual Display is in Pause state.
139 * Mark all application layers as OVERLAY so that
140 * GPU will not compose.
141 */
Raj Kamale012e0e2014-05-28 23:45:19 +0530142 Writeback::getInstance(); //Ensure that WB is active during pause
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800143 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
144 hwc_layer_1_t *layer = &list->hwLayers[i];
145 layer->compositionType = HWC_OVERLAY;
146 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800147 }
148 }
149 return 0;
150}
151
152int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
153 ATRACE_CALL();
154 int ret = 0;
155 const int dpy = HWC_DISPLAY_VIRTUAL;
156
Tatenda Chipeperekwaf19f84d2014-01-17 12:43:29 -0800157 if (list && list->outbuf && list->numHwLayers > 0) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530158 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800159 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
160
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800161 if(ctx->dpyAttr[dpy].connected
162 && (!ctx->dpyAttr[dpy].isPause))
163 {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800164 private_handle_t *ohnd = (private_handle_t *)list->outbuf;
Tatenda Chipeperekwaa2fdebe2014-01-20 12:29:50 -0800165 int format = ohnd->format;
166 if (format == HAL_PIXEL_FORMAT_RGBA_8888)
167 format = HAL_PIXEL_FORMAT_RGBX_8888;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800168 Writeback::getInstance()->setOutputFormat(
Tatenda Chipeperekwaa2fdebe2014-01-20 12:29:50 -0800169 utils::getMdpFormat(format));
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800170
Tatenda Chipeperekwa92961f82014-01-17 13:04:28 -0800171 // Configure WB as secure if the output buffer handle is secure.
172 if(isSecureBuffer(ohnd)){
173 if(! Writeback::getInstance()->setSecure(true))
174 {
175 ALOGE("Failed to set WB as secure for virtual display");
176 return false;
177 }
178 }
179
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800180 int fd = -1; //FenceFD from the Copybit
181 hwc_sync(ctx, list, dpy, fd);
182
Tatenda Chipeperekwa523eac52014-05-29 14:58:39 -0700183 // Dump the layers for virtual
184 if(ctx->mHwcDebug[dpy])
185 ctx->mHwcDebug[dpy]->dumpLayers(list);
186
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800187 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
188 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
189 ret = -1;
190 }
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800191 // We need an FB layer handle check to cater for this usecase:
192 // Video is playing in landscape on primary, then launch
193 // ScreenRecord app.
194 // In this scenario, the first VDS draw call will have HWC
195 // composition and VDS does nit involve GPU to get eglSwapBuffer
196 // to get valid fb handle.
197 if (fbLayer->handle && !ctx->mFBUpdate[dpy]->draw(ctx,
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800198 (private_handle_t *)fbLayer->handle)) {
199 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
200 ret = -1;
201 }
202
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530203 Writeback::getInstance()->queueBuffer(ohnd->fd,
204 (uint32_t)ohnd->offset);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800205 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
206 ALOGE("%s: display commit fail!", __FUNCTION__);
207 ret = -1;
208 }
209
Tatenda Chipeperekwa06af9cb2014-08-26 14:51:05 -0700210 if(sVDDumpEnabled) {
Tatenda Chipeperekwa523eac52014-05-29 14:58:39 -0700211 char bufferName[128];
212 // Dumping frame buffer
213 sync_wait(fbLayer->acquireFenceFd, 1000);
214 snprintf(bufferName, sizeof(bufferName), "vds.fb");
215 dumpBuffer((private_handle_t *)fbLayer->handle, bufferName);
216 // Dumping WB output for non-secure session
217 if(!isSecureBuffer(ohnd)) {
218 sync_wait(list->retireFenceFd, 1000);
219 snprintf(bufferName, sizeof(bufferName), "vds.wb");
220 dumpBuffer(ohnd, bufferName);
221 }
222 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800223 } else if(list->outbufAcquireFenceFd >= 0) {
224 //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
225 //which will make sure, the framework waits on it and closes it.
226 //The other way is to wait on outbufFenceFd ourselves, close it and
227 //set retireFenceFd to -1. Since we want hwc to be async, choosing
228 //the former.
229 //Also dup because, the closeAcquireFds() will close the outbufFence
230 list->retireFenceFd = dup(list->outbufAcquireFenceFd);
231 }
232 }
233
234 closeAcquireFds(list);
235 return ret;
236}
237
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800238void HWCVirtualVDS::pause(hwc_context_t* ctx, int dpy) {
239 {
240 Locker::Autolock _l(ctx->mDrawLock);
241 ctx->dpyAttr[dpy].isActive = true;
242 ctx->dpyAttr[dpy].isPause = true;
243 ctx->proc->invalidate(ctx->proc);
244 }
245 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
246 * 2 / 1000);
Raj Kamale012e0e2014-05-28 23:45:19 +0530247 // At this point all the pipes used by External have been
248 // marked as UNSET.
249 {
250 Locker::Autolock _l(ctx->mDrawLock);
251 // Perform commit to unstage the pipes.
252 if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
253 ALOGE("%s: display commit fail! for %d dpy",
254 __FUNCTION__, dpy);
255 }
Raj Kamaldf3d1d22014-05-30 21:23:27 +0530256 ctx->proc->invalidate(ctx->proc);
Raj Kamale012e0e2014-05-28 23:45:19 +0530257 }
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800258 return;
259}
260
261void HWCVirtualVDS::resume(hwc_context_t* ctx, int dpy) {
262 {
263 Locker::Autolock _l(ctx->mDrawLock);
264 ctx->dpyAttr[dpy].isConfiguring = true;
265 ctx->dpyAttr[dpy].isActive = true;
266 ctx->proc->invalidate(ctx->proc);
267 }
268 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
269 * 2 / 1000);
270 //At this point external has all the pipes it would need.
271 {
272 Locker::Autolock _l(ctx->mDrawLock);
273 ctx->dpyAttr[dpy].isPause = false;
274 ctx->proc->invalidate(ctx->proc);
275 }
276 return;
277}
278
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800279/* Implementation for HWCVirtualV4L2 class */
280
281int HWCVirtualV4L2::prepare(hwc_composer_device_1 *dev,
282 hwc_display_contents_1_t *list) {
283 ATRACE_CALL();
284
285 hwc_context_t* ctx = (hwc_context_t*)(dev);
286 const int dpy = HWC_DISPLAY_VIRTUAL;
287
288 if (LIKELY(list && list->numHwLayers > 1) &&
289 ctx->dpyAttr[dpy].isActive &&
Raj Kamal5ef25b82014-07-03 17:33:54 +0530290 ctx->dpyAttr[dpy].connected) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530291 reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800292 if(!ctx->dpyAttr[dpy].isPause) {
293 ctx->dpyAttr[dpy].isConfiguring = false;
294 setListStats(ctx, list, dpy);
295 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
296 const int fbZ = 0;
Saurabh Shahef19fe32014-04-22 15:31:58 -0700297 if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
298 {
299 ctx->mOverlay->clear(dpy);
300 ctx->mLayerRotMap[dpy]->clear();
301 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800302 }
303 } else {
304 /* Virtual Display is in Pause state.
305 * Mark all application layers as OVERLAY so that
306 * GPU will not compose.
307 */
308 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
309 hwc_layer_1_t *layer = &list->hwLayers[i];
310 layer->compositionType = HWC_OVERLAY;
311 }
312 }
313 }
314 return 0;
315}
316
317int HWCVirtualV4L2::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
318 ATRACE_CALL();
319 int ret = 0;
320
321 const int dpy = HWC_DISPLAY_VIRTUAL;
322
323 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
324 ctx->dpyAttr[dpy].connected &&
Raj Kamal5ef25b82014-07-03 17:33:54 +0530325 !ctx->dpyAttr[dpy].isPause) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530326 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800327 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
328 int fd = -1; //FenceFD from the Copybit(valid in async mode)
329 bool copybitDone = false;
330 if(ctx->mCopyBit[dpy])
331 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
332
333 if(list->numHwLayers > 1)
334 hwc_sync(ctx, list, dpy, fd);
335
336 // Dump the layers for virtual
337 if(ctx->mHwcDebug[dpy])
338 ctx->mHwcDebug[dpy]->dumpLayers(list);
339
340 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
341 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
342 ret = -1;
343 }
344
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800345 private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
Ramkumar Radhakrishnan3d863772014-08-12 16:49:03 -0700346 if(copybitDone) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800347 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
348 }
349
Ramkumar Radhakrishnan3d863772014-08-12 16:49:03 -0700350 if(hnd) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800351 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
352 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
353 ret = -1;
354 }
355 }
356
357 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
358 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
359 ret = -1;
360 }
361 }
362
363 closeAcquireFds(list);
364
Baldev Sahuec852382014-02-14 08:36:00 +0530365 if (list && list->outbuf && (list->retireFenceFd < 0) ) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800366 // SF assumes HWC waits for the acquire fence and returns a new fence
367 // that signals when we're done. Since we don't wait, and also don't
368 // touch the buffer, we can just handle the acquire fence back to SF
369 // as the retire fence.
370 list->retireFenceFd = list->outbufAcquireFenceFd;
371 }
372
373 return ret;
374}
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800375
376void HWCVirtualV4L2::pause(hwc_context_t* ctx, int dpy) {
377 {
378 Locker::Autolock _l(ctx->mDrawLock);
379 ctx->dpyAttr[dpy].isActive = true;
380 ctx->dpyAttr[dpy].isPause = true;
381 ctx->proc->invalidate(ctx->proc);
382 }
383 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
384 * 2 / 1000);
385 // At this point all the pipes used by External have been
386 // marked as UNSET.
387 {
388 Locker::Autolock _l(ctx->mDrawLock);
389 // Perform commit to unstage the pipes.
390 if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
391 ALOGE("%s: display commit fail! for %d dpy",
392 __FUNCTION__, dpy);
393 }
394 }
395 return;
396}
397
398void HWCVirtualV4L2::resume(hwc_context_t* ctx, int dpy){
399 //Treat Resume as Online event
400 //Since external didnt have any pipes, force primary to give up
401 //its pipes; we don't allow inter-mixer pipe transfers.
402 {
403 Locker::Autolock _l(ctx->mDrawLock);
404
405 // A dynamic resolution change (DRC) can be made for a WiFi
406 // display. In order to support the resolution change, we
407 // need to reconfigure the corresponding display attributes.
408 // Since DRC is only on WiFi display, we only need to call
409 // configure() on the VirtualDisplay device.
410 //TODO: clean up
411 if(dpy == HWC_DISPLAY_VIRTUAL)
412 ctx->mVirtualDisplay->configure();
413
414 ctx->dpyAttr[dpy].isConfiguring = true;
415 ctx->dpyAttr[dpy].isActive = true;
416 ctx->proc->invalidate(ctx->proc);
417 }
418 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
419 * 2 / 1000);
420 //At this point external has all the pipes it would need.
421 {
422 Locker::Autolock _l(ctx->mDrawLock);
423 ctx->dpyAttr[dpy].isPause = false;
424 ctx->proc->invalidate(ctx->proc);
425 }
426 return;
427}