blob: 10ed9d1ce041ae00b9afd0865699deed50feef1d [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;
129 ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
130 }
131 } else {
132 /* Virtual Display is in Pause state.
133 * Mark all application layers as OVERLAY so that
134 * GPU will not compose.
135 */
136 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
137 hwc_layer_1_t *layer = &list->hwLayers[i];
138 layer->compositionType = HWC_OVERLAY;
139 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800140 }
141 }
142 return 0;
143}
144
145int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
146 ATRACE_CALL();
147 int ret = 0;
148 const int dpy = HWC_DISPLAY_VIRTUAL;
149
Tatenda Chipeperekwaf19f84d2014-01-17 12:43:29 -0800150 if (list && list->outbuf && list->numHwLayers > 0) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530151 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800152 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
153
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800154 if(ctx->dpyAttr[dpy].connected
155 && (!ctx->dpyAttr[dpy].isPause))
156 {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800157 private_handle_t *ohnd = (private_handle_t *)list->outbuf;
Tatenda Chipeperekwaa2fdebe2014-01-20 12:29:50 -0800158 int format = ohnd->format;
159 if (format == HAL_PIXEL_FORMAT_RGBA_8888)
160 format = HAL_PIXEL_FORMAT_RGBX_8888;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800161 Writeback::getInstance()->setOutputFormat(
Tatenda Chipeperekwaa2fdebe2014-01-20 12:29:50 -0800162 utils::getMdpFormat(format));
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800163
Tatenda Chipeperekwa92961f82014-01-17 13:04:28 -0800164 // Configure WB as secure if the output buffer handle is secure.
165 if(isSecureBuffer(ohnd)){
166 if(! Writeback::getInstance()->setSecure(true))
167 {
168 ALOGE("Failed to set WB as secure for virtual display");
169 return false;
170 }
171 }
172
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800173 int fd = -1; //FenceFD from the Copybit
174 hwc_sync(ctx, list, dpy, fd);
175
176 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
177 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
178 ret = -1;
179 }
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800180 // We need an FB layer handle check to cater for this usecase:
181 // Video is playing in landscape on primary, then launch
182 // ScreenRecord app.
183 // In this scenario, the first VDS draw call will have HWC
184 // composition and VDS does nit involve GPU to get eglSwapBuffer
185 // to get valid fb handle.
186 if (fbLayer->handle && !ctx->mFBUpdate[dpy]->draw(ctx,
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800187 (private_handle_t *)fbLayer->handle)) {
188 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
189 ret = -1;
190 }
191
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530192 Writeback::getInstance()->queueBuffer(ohnd->fd,
193 (uint32_t)ohnd->offset);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800194 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
195 ALOGE("%s: display commit fail!", __FUNCTION__);
196 ret = -1;
197 }
198
199 } else if(list->outbufAcquireFenceFd >= 0) {
200 //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
201 //which will make sure, the framework waits on it and closes it.
202 //The other way is to wait on outbufFenceFd ourselves, close it and
203 //set retireFenceFd to -1. Since we want hwc to be async, choosing
204 //the former.
205 //Also dup because, the closeAcquireFds() will close the outbufFence
206 list->retireFenceFd = dup(list->outbufAcquireFenceFd);
207 }
208 }
209
210 closeAcquireFds(list);
211 return ret;
212}
213
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800214void HWCVirtualVDS::pause(hwc_context_t* ctx, int dpy) {
215 {
216 Locker::Autolock _l(ctx->mDrawLock);
217 ctx->dpyAttr[dpy].isActive = true;
218 ctx->dpyAttr[dpy].isPause = true;
219 ctx->proc->invalidate(ctx->proc);
220 }
221 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
222 * 2 / 1000);
223 return;
224}
225
226void HWCVirtualVDS::resume(hwc_context_t* ctx, int dpy) {
227 {
228 Locker::Autolock _l(ctx->mDrawLock);
229 ctx->dpyAttr[dpy].isConfiguring = true;
230 ctx->dpyAttr[dpy].isActive = true;
231 ctx->proc->invalidate(ctx->proc);
232 }
233 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
234 * 2 / 1000);
235 //At this point external has all the pipes it would need.
236 {
237 Locker::Autolock _l(ctx->mDrawLock);
238 ctx->dpyAttr[dpy].isPause = false;
239 ctx->proc->invalidate(ctx->proc);
240 }
241 return;
242}
243
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800244/* Implementation for HWCVirtualV4L2 class */
245
246int HWCVirtualV4L2::prepare(hwc_composer_device_1 *dev,
247 hwc_display_contents_1_t *list) {
248 ATRACE_CALL();
249
250 hwc_context_t* ctx = (hwc_context_t*)(dev);
251 const int dpy = HWC_DISPLAY_VIRTUAL;
252
253 if (LIKELY(list && list->numHwLayers > 1) &&
254 ctx->dpyAttr[dpy].isActive &&
Raj Kamal52b4fdb2014-01-27 19:35:13 +0530255 ctx->dpyAttr[dpy].connected &&
256 canUseMDPforVirtualDisplay(ctx,list)) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530257 reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800258 if(!ctx->dpyAttr[dpy].isPause) {
259 ctx->dpyAttr[dpy].isConfiguring = false;
260 setListStats(ctx, list, dpy);
261 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
262 const int fbZ = 0;
Manoj Kumar AVM0901c042014-02-10 20:06:08 -0800263 ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800264 }
265 } else {
266 /* Virtual Display is in Pause state.
267 * Mark all application layers as OVERLAY so that
268 * GPU will not compose.
269 */
270 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
271 hwc_layer_1_t *layer = &list->hwLayers[i];
272 layer->compositionType = HWC_OVERLAY;
273 }
274 }
275 }
276 return 0;
277}
278
279int HWCVirtualV4L2::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
280 ATRACE_CALL();
281 int ret = 0;
282
283 const int dpy = HWC_DISPLAY_VIRTUAL;
284
285 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
286 ctx->dpyAttr[dpy].connected &&
Raj Kamal52b4fdb2014-01-27 19:35:13 +0530287 (!ctx->dpyAttr[dpy].isPause) &&
288 canUseMDPforVirtualDisplay(ctx,list)) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530289 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800290 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
291 int fd = -1; //FenceFD from the Copybit(valid in async mode)
292 bool copybitDone = false;
293 if(ctx->mCopyBit[dpy])
294 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
295
296 if(list->numHwLayers > 1)
297 hwc_sync(ctx, list, dpy, fd);
298
299 // Dump the layers for virtual
300 if(ctx->mHwcDebug[dpy])
301 ctx->mHwcDebug[dpy]->dumpLayers(list);
302
303 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
304 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
305 ret = -1;
306 }
307
308 int extOnlyLayerIndex =
309 ctx->listStats[dpy].extOnlyLayerIndex;
310
311 private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
312 if(extOnlyLayerIndex!= -1) {
313 hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
314 hnd = (private_handle_t *)extLayer->handle;
315 } else if(copybitDone) {
316 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
317 }
318
319 if(hnd && !isYuvBuffer(hnd)) {
320 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
321 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
322 ret = -1;
323 }
324 }
325
326 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
327 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
328 ret = -1;
329 }
330 }
331
332 closeAcquireFds(list);
333
Baldev Sahuec852382014-02-14 08:36:00 +0530334 if (list && list->outbuf && (list->retireFenceFd < 0) ) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800335 // SF assumes HWC waits for the acquire fence and returns a new fence
336 // that signals when we're done. Since we don't wait, and also don't
337 // touch the buffer, we can just handle the acquire fence back to SF
338 // as the retire fence.
339 list->retireFenceFd = list->outbufAcquireFenceFd;
340 }
341
342 return ret;
343}
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800344
345void HWCVirtualV4L2::pause(hwc_context_t* ctx, int dpy) {
346 {
347 Locker::Autolock _l(ctx->mDrawLock);
348 ctx->dpyAttr[dpy].isActive = true;
349 ctx->dpyAttr[dpy].isPause = true;
350 ctx->proc->invalidate(ctx->proc);
351 }
352 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
353 * 2 / 1000);
354 // At this point all the pipes used by External have been
355 // marked as UNSET.
356 {
357 Locker::Autolock _l(ctx->mDrawLock);
358 // Perform commit to unstage the pipes.
359 if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
360 ALOGE("%s: display commit fail! for %d dpy",
361 __FUNCTION__, dpy);
362 }
363 }
364 return;
365}
366
367void HWCVirtualV4L2::resume(hwc_context_t* ctx, int dpy){
368 //Treat Resume as Online event
369 //Since external didnt have any pipes, force primary to give up
370 //its pipes; we don't allow inter-mixer pipe transfers.
371 {
372 Locker::Autolock _l(ctx->mDrawLock);
373
374 // A dynamic resolution change (DRC) can be made for a WiFi
375 // display. In order to support the resolution change, we
376 // need to reconfigure the corresponding display attributes.
377 // Since DRC is only on WiFi display, we only need to call
378 // configure() on the VirtualDisplay device.
379 //TODO: clean up
380 if(dpy == HWC_DISPLAY_VIRTUAL)
381 ctx->mVirtualDisplay->configure();
382
383 ctx->dpyAttr[dpy].isConfiguring = true;
384 ctx->dpyAttr[dpy].isActive = true;
385 ctx->proc->invalidate(ctx->proc);
386 }
387 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
388 * 2 / 1000);
389 //At this point external has all the pipes it would need.
390 {
391 Locker::Autolock _l(ctx->mDrawLock);
392 ctx->dpyAttr[dpy].isPause = false;
393 ctx->proc->invalidate(ctx->proc);
394 }
395 return;
396}