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