blob: adda35b7a28d3308865a730b2cbfd8eb6cf4d7f3 [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
Raj kamal59fea562014-04-01 16:52:19 +053038HWCVirtualBase* HWCVirtualBase::getObject(bool isVDSEnabled) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080039
Raj kamal59fea562014-04-01 16:52:19 +053040 if(isVDSEnabled) {
41 ALOGD_IF(HWCVIRTUAL_LOG, "%s: VDS is enabled for Virtual display",
42 __FUNCTION__);
43 return new HWCVirtualVDS();
44 } else {
45 ALOGD_IF(HWCVIRTUAL_LOG, "%s: V4L2 is enabled for Virtual display",
46 __FUNCTION__);
47 return new HWCVirtualV4L2();
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080048 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080049}
50
51void HWCVirtualVDS::init(hwc_context_t *ctx) {
52 const int dpy = HWC_DISPLAY_VIRTUAL;
53 ctx->mFBUpdate[dpy] =
54 IFBUpdate::getObject(ctx, dpy);
55 ctx->mMDPComp[dpy] = MDPComp::getObject(ctx, dpy);
56
57 if(ctx->mFBUpdate[dpy])
58 ctx->mFBUpdate[dpy]->reset();
59 if(ctx->mMDPComp[dpy])
60 ctx->mMDPComp[dpy]->reset();
61}
62
Arun Kumar K.R2aa44c62014-01-21 23:08:28 -080063void HWCVirtualVDS::destroy(hwc_context_t *ctx, size_t /*numDisplays*/,
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080064 hwc_display_contents_1_t** displays) {
65 int dpy = HWC_DISPLAY_VIRTUAL;
66
67 //Cleanup virtual display objs, since there is no explicit disconnect
Raj Kamal52b4fdb2014-01-27 19:35:13 +053068 if(ctx->dpyAttr[dpy].connected && (displays[dpy] == NULL)) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080069 ctx->dpyAttr[dpy].connected = false;
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -080070 ctx->dpyAttr[dpy].isPause = false;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080071
72 if(ctx->mFBUpdate[dpy]) {
73 delete ctx->mFBUpdate[dpy];
74 ctx->mFBUpdate[dpy] = NULL;
75 }
76 if(ctx->mMDPComp[dpy]) {
77 delete ctx->mMDPComp[dpy];
78 ctx->mMDPComp[dpy] = NULL;
79 }
Tatenda Chipeperekwa92961f82014-01-17 13:04:28 -080080 // We reset the WB session to non-secure when the virtual display
81 // has been disconnected.
82 if(!Writeback::getInstance()->setSecure(false)) {
83 ALOGE("Failure while attempting to reset WB session.");
84 }
Raj kamal59fea562014-04-01 16:52:19 +053085 ctx->mWfdSyncLock.lock();
86 ctx->mWfdSyncLock.signal();
87 ctx->mWfdSyncLock.unlock();
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080088 }
89}
90
91int HWCVirtualVDS::prepare(hwc_composer_device_1 *dev,
92 hwc_display_contents_1_t *list) {
93 ATRACE_CALL();
94 //XXX: Fix when framework support is added
95 hwc_context_t* ctx = (hwc_context_t*)(dev);
96 const int dpy = HWC_DISPLAY_VIRTUAL;
97
Tatenda Chipeperekwab0a9f9d2014-01-20 09:23:21 -080098 if (list && list->outbuf && list->numHwLayers > 0) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +053099 reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
100 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800101 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
102 int fbWidth = 0, fbHeight = 0;
103 getLayerResolution(fbLayer, fbWidth, fbHeight);
104 ctx->dpyAttr[dpy].xres = fbWidth;
105 ctx->dpyAttr[dpy].yres = fbHeight;
106
107 if(ctx->dpyAttr[dpy].connected == false) {
108 ctx->dpyAttr[dpy].connected = true;
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800109 ctx->dpyAttr[dpy].isPause = false;
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800110 // We set the vsync period to the primary refresh rate, leaving
111 // it up to the consumer to decide how fast to consume frames.
112 ctx->dpyAttr[dpy].vsync_period
113 = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800114 init(ctx);
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800115 // XXX: for architectures with limited resources we would normally
116 // allow one padding round to free up resources but this breaks
117 // certain use cases.
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800118 }
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800119 if(!ctx->dpyAttr[dpy].isPause) {
120 ctx->dpyAttr[dpy].isConfiguring = false;
121 ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
122 private_handle_t *ohnd = (private_handle_t *)list->outbuf;
123 Writeback::getInstance()->configureDpyInfo(ohnd->width,
124 ohnd->height);
125 setListStats(ctx, list, dpy);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800126
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800127 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
128 const int fbZ = 0;
Saurabh Shahef19fe32014-04-22 15:31:58 -0700129 if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
130 {
131 ctx->mOverlay->clear(dpy);
132 ctx->mLayerRotMap[dpy]->clear();
133 }
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800134 }
135 } else {
136 /* Virtual Display is in Pause state.
137 * Mark all application layers as OVERLAY so that
138 * GPU will not compose.
139 */
Raj Kamale012e0e2014-05-28 23:45:19 +0530140 Writeback::getInstance(); //Ensure that WB is active during pause
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800141 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
142 hwc_layer_1_t *layer = &list->hwLayers[i];
143 layer->compositionType = HWC_OVERLAY;
144 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800145 }
146 }
147 return 0;
148}
149
150int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
151 ATRACE_CALL();
152 int ret = 0;
153 const int dpy = HWC_DISPLAY_VIRTUAL;
154
Tatenda Chipeperekwaf19f84d2014-01-17 12:43:29 -0800155 if (list && list->outbuf && list->numHwLayers > 0) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530156 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800157 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
158
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800159 if(ctx->dpyAttr[dpy].connected
160 && (!ctx->dpyAttr[dpy].isPause))
161 {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800162 private_handle_t *ohnd = (private_handle_t *)list->outbuf;
Tatenda Chipeperekwaa2fdebe2014-01-20 12:29:50 -0800163 int format = ohnd->format;
164 if (format == HAL_PIXEL_FORMAT_RGBA_8888)
165 format = HAL_PIXEL_FORMAT_RGBX_8888;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800166 Writeback::getInstance()->setOutputFormat(
Tatenda Chipeperekwaa2fdebe2014-01-20 12:29:50 -0800167 utils::getMdpFormat(format));
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800168
Tatenda Chipeperekwa92961f82014-01-17 13:04:28 -0800169 // Configure WB as secure if the output buffer handle is secure.
170 if(isSecureBuffer(ohnd)){
171 if(! Writeback::getInstance()->setSecure(true))
172 {
173 ALOGE("Failed to set WB as secure for virtual display");
174 return false;
175 }
176 }
177
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800178 int fd = -1; //FenceFD from the Copybit
179 hwc_sync(ctx, list, dpy, fd);
180
181 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
182 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
183 ret = -1;
184 }
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800185 // We need an FB layer handle check to cater for this usecase:
186 // Video is playing in landscape on primary, then launch
187 // ScreenRecord app.
188 // In this scenario, the first VDS draw call will have HWC
189 // composition and VDS does nit involve GPU to get eglSwapBuffer
190 // to get valid fb handle.
191 if (fbLayer->handle && !ctx->mFBUpdate[dpy]->draw(ctx,
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800192 (private_handle_t *)fbLayer->handle)) {
193 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
194 ret = -1;
195 }
196
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530197 Writeback::getInstance()->queueBuffer(ohnd->fd,
198 (uint32_t)ohnd->offset);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800199 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
200 ALOGE("%s: display commit fail!", __FUNCTION__);
201 ret = -1;
202 }
203
204 } else if(list->outbufAcquireFenceFd >= 0) {
205 //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
206 //which will make sure, the framework waits on it and closes it.
207 //The other way is to wait on outbufFenceFd ourselves, close it and
208 //set retireFenceFd to -1. Since we want hwc to be async, choosing
209 //the former.
210 //Also dup because, the closeAcquireFds() will close the outbufFence
211 list->retireFenceFd = dup(list->outbufAcquireFenceFd);
212 }
213 }
214
215 closeAcquireFds(list);
216 return ret;
217}
218
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800219void HWCVirtualVDS::pause(hwc_context_t* ctx, int dpy) {
220 {
221 Locker::Autolock _l(ctx->mDrawLock);
222 ctx->dpyAttr[dpy].isActive = true;
223 ctx->dpyAttr[dpy].isPause = true;
224 ctx->proc->invalidate(ctx->proc);
225 }
226 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
227 * 2 / 1000);
Raj Kamale012e0e2014-05-28 23:45:19 +0530228 // At this point all the pipes used by External have been
229 // marked as UNSET.
230 {
231 Locker::Autolock _l(ctx->mDrawLock);
232 // Perform commit to unstage the pipes.
233 if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
234 ALOGE("%s: display commit fail! for %d dpy",
235 __FUNCTION__, dpy);
236 }
Raj Kamaldf3d1d22014-05-30 21:23:27 +0530237 ctx->proc->invalidate(ctx->proc);
Raj Kamale012e0e2014-05-28 23:45:19 +0530238 }
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800239 return;
240}
241
242void HWCVirtualVDS::resume(hwc_context_t* ctx, int dpy) {
243 {
244 Locker::Autolock _l(ctx->mDrawLock);
245 ctx->dpyAttr[dpy].isConfiguring = true;
246 ctx->dpyAttr[dpy].isActive = true;
247 ctx->proc->invalidate(ctx->proc);
248 }
249 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
250 * 2 / 1000);
251 //At this point external has all the pipes it would need.
252 {
253 Locker::Autolock _l(ctx->mDrawLock);
254 ctx->dpyAttr[dpy].isPause = false;
255 ctx->proc->invalidate(ctx->proc);
256 }
257 return;
258}
259
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800260/* Implementation for HWCVirtualV4L2 class */
261
262int HWCVirtualV4L2::prepare(hwc_composer_device_1 *dev,
263 hwc_display_contents_1_t *list) {
264 ATRACE_CALL();
265
266 hwc_context_t* ctx = (hwc_context_t*)(dev);
267 const int dpy = HWC_DISPLAY_VIRTUAL;
268
269 if (LIKELY(list && list->numHwLayers > 1) &&
270 ctx->dpyAttr[dpy].isActive &&
Raj Kamal52b4fdb2014-01-27 19:35:13 +0530271 ctx->dpyAttr[dpy].connected &&
272 canUseMDPforVirtualDisplay(ctx,list)) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530273 reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800274 if(!ctx->dpyAttr[dpy].isPause) {
275 ctx->dpyAttr[dpy].isConfiguring = false;
276 setListStats(ctx, list, dpy);
277 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
278 const int fbZ = 0;
Saurabh Shahef19fe32014-04-22 15:31:58 -0700279 if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
280 {
281 ctx->mOverlay->clear(dpy);
282 ctx->mLayerRotMap[dpy]->clear();
283 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800284 }
285 } else {
286 /* Virtual Display is in Pause state.
287 * Mark all application layers as OVERLAY so that
288 * GPU will not compose.
289 */
290 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
291 hwc_layer_1_t *layer = &list->hwLayers[i];
292 layer->compositionType = HWC_OVERLAY;
293 }
294 }
295 }
296 return 0;
297}
298
299int HWCVirtualV4L2::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
300 ATRACE_CALL();
301 int ret = 0;
302
303 const int dpy = HWC_DISPLAY_VIRTUAL;
304
305 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
306 ctx->dpyAttr[dpy].connected &&
Raj Kamal52b4fdb2014-01-27 19:35:13 +0530307 (!ctx->dpyAttr[dpy].isPause) &&
308 canUseMDPforVirtualDisplay(ctx,list)) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530309 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800310 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
311 int fd = -1; //FenceFD from the Copybit(valid in async mode)
312 bool copybitDone = false;
313 if(ctx->mCopyBit[dpy])
314 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
315
316 if(list->numHwLayers > 1)
317 hwc_sync(ctx, list, dpy, fd);
318
319 // Dump the layers for virtual
320 if(ctx->mHwcDebug[dpy])
321 ctx->mHwcDebug[dpy]->dumpLayers(list);
322
323 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
324 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
325 ret = -1;
326 }
327
328 int extOnlyLayerIndex =
329 ctx->listStats[dpy].extOnlyLayerIndex;
330
331 private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
332 if(extOnlyLayerIndex!= -1) {
333 hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
334 hnd = (private_handle_t *)extLayer->handle;
335 } else if(copybitDone) {
336 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
337 }
338
339 if(hnd && !isYuvBuffer(hnd)) {
340 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
341 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
342 ret = -1;
343 }
344 }
345
346 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
347 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
348 ret = -1;
349 }
350 }
351
352 closeAcquireFds(list);
353
Baldev Sahuec852382014-02-14 08:36:00 +0530354 if (list && list->outbuf && (list->retireFenceFd < 0) ) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800355 // SF assumes HWC waits for the acquire fence and returns a new fence
356 // that signals when we're done. Since we don't wait, and also don't
357 // touch the buffer, we can just handle the acquire fence back to SF
358 // as the retire fence.
359 list->retireFenceFd = list->outbufAcquireFenceFd;
360 }
361
362 return ret;
363}
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800364
365void HWCVirtualV4L2::pause(hwc_context_t* ctx, int dpy) {
366 {
367 Locker::Autolock _l(ctx->mDrawLock);
368 ctx->dpyAttr[dpy].isActive = true;
369 ctx->dpyAttr[dpy].isPause = true;
370 ctx->proc->invalidate(ctx->proc);
371 }
372 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
373 * 2 / 1000);
374 // At this point all the pipes used by External have been
375 // marked as UNSET.
376 {
377 Locker::Autolock _l(ctx->mDrawLock);
378 // Perform commit to unstage the pipes.
379 if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
380 ALOGE("%s: display commit fail! for %d dpy",
381 __FUNCTION__, dpy);
382 }
383 }
384 return;
385}
386
387void HWCVirtualV4L2::resume(hwc_context_t* ctx, int dpy){
388 //Treat Resume as Online event
389 //Since external didnt have any pipes, force primary to give up
390 //its pipes; we don't allow inter-mixer pipe transfers.
391 {
392 Locker::Autolock _l(ctx->mDrawLock);
393
394 // A dynamic resolution change (DRC) can be made for a WiFi
395 // display. In order to support the resolution change, we
396 // need to reconfigure the corresponding display attributes.
397 // Since DRC is only on WiFi display, we only need to call
398 // configure() on the VirtualDisplay device.
399 //TODO: clean up
400 if(dpy == HWC_DISPLAY_VIRTUAL)
401 ctx->mVirtualDisplay->configure();
402
403 ctx->dpyAttr[dpy].isConfiguring = true;
404 ctx->dpyAttr[dpy].isActive = true;
405 ctx->proc->invalidate(ctx->proc);
406 }
407 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
408 * 2 / 1000);
409 //At this point external has all the pipes it would need.
410 {
411 Locker::Autolock _l(ctx->mDrawLock);
412 ctx->dpyAttr[dpy].isPause = false;
413 ctx->proc->invalidate(ctx->proc);
414 }
415 return;
416}