blob: f68d08f0e7306cd61fb67c9aac2e37cdda4ba63e [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) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +053098 reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
99 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800100 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) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530150 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800151 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
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530191 Writeback::getInstance()->queueBuffer(ohnd->fd,
192 (uint32_t)ohnd->offset);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800193 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
194 ALOGE("%s: display commit fail!", __FUNCTION__);
195 ret = -1;
196 }
197
198 } else if(list->outbufAcquireFenceFd >= 0) {
199 //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
200 //which will make sure, the framework waits on it and closes it.
201 //The other way is to wait on outbufFenceFd ourselves, close it and
202 //set retireFenceFd to -1. Since we want hwc to be async, choosing
203 //the former.
204 //Also dup because, the closeAcquireFds() will close the outbufFence
205 list->retireFenceFd = dup(list->outbufAcquireFenceFd);
206 }
207 }
208
209 closeAcquireFds(list);
210 return ret;
211}
212
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800213void HWCVirtualVDS::pause(hwc_context_t* ctx, int dpy) {
214 {
215 Locker::Autolock _l(ctx->mDrawLock);
216 ctx->dpyAttr[dpy].isActive = true;
217 ctx->dpyAttr[dpy].isPause = true;
218 ctx->proc->invalidate(ctx->proc);
219 }
220 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
221 * 2 / 1000);
222 return;
223}
224
225void HWCVirtualVDS::resume(hwc_context_t* ctx, int dpy) {
226 {
227 Locker::Autolock _l(ctx->mDrawLock);
228 ctx->dpyAttr[dpy].isConfiguring = true;
229 ctx->dpyAttr[dpy].isActive = true;
230 ctx->proc->invalidate(ctx->proc);
231 }
232 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
233 * 2 / 1000);
234 //At this point external has all the pipes it would need.
235 {
236 Locker::Autolock _l(ctx->mDrawLock);
237 ctx->dpyAttr[dpy].isPause = false;
238 ctx->proc->invalidate(ctx->proc);
239 }
240 return;
241}
242
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800243/* Implementation for HWCVirtualV4L2 class */
244
245int HWCVirtualV4L2::prepare(hwc_composer_device_1 *dev,
246 hwc_display_contents_1_t *list) {
247 ATRACE_CALL();
248
249 hwc_context_t* ctx = (hwc_context_t*)(dev);
250 const int dpy = HWC_DISPLAY_VIRTUAL;
251
252 if (LIKELY(list && list->numHwLayers > 1) &&
253 ctx->dpyAttr[dpy].isActive &&
Raj Kamal52b4fdb2014-01-27 19:35:13 +0530254 ctx->dpyAttr[dpy].connected &&
255 canUseMDPforVirtualDisplay(ctx,list)) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530256 reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800257 if(!ctx->dpyAttr[dpy].isPause) {
258 ctx->dpyAttr[dpy].isConfiguring = false;
259 setListStats(ctx, list, dpy);
260 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
261 const int fbZ = 0;
Manoj Kumar AVM0901c042014-02-10 20:06:08 -0800262 ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800263 }
264 } else {
265 /* Virtual Display is in Pause state.
266 * Mark all application layers as OVERLAY so that
267 * GPU will not compose.
268 */
269 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
270 hwc_layer_1_t *layer = &list->hwLayers[i];
271 layer->compositionType = HWC_OVERLAY;
272 }
273 }
274 }
275 return 0;
276}
277
278int HWCVirtualV4L2::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
279 ATRACE_CALL();
280 int ret = 0;
281
282 const int dpy = HWC_DISPLAY_VIRTUAL;
283
284 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
285 ctx->dpyAttr[dpy].connected &&
Raj Kamal52b4fdb2014-01-27 19:35:13 +0530286 (!ctx->dpyAttr[dpy].isPause) &&
287 canUseMDPforVirtualDisplay(ctx,list)) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530288 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800289 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
290 int fd = -1; //FenceFD from the Copybit(valid in async mode)
291 bool copybitDone = false;
292 if(ctx->mCopyBit[dpy])
293 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
294
295 if(list->numHwLayers > 1)
296 hwc_sync(ctx, list, dpy, fd);
297
298 // Dump the layers for virtual
299 if(ctx->mHwcDebug[dpy])
300 ctx->mHwcDebug[dpy]->dumpLayers(list);
301
302 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
303 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
304 ret = -1;
305 }
306
307 int extOnlyLayerIndex =
308 ctx->listStats[dpy].extOnlyLayerIndex;
309
310 private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
311 if(extOnlyLayerIndex!= -1) {
312 hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
313 hnd = (private_handle_t *)extLayer->handle;
314 } else if(copybitDone) {
315 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
316 }
317
318 if(hnd && !isYuvBuffer(hnd)) {
319 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
320 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
321 ret = -1;
322 }
323 }
324
325 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
326 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
327 ret = -1;
328 }
329 }
330
331 closeAcquireFds(list);
332
Baldev Sahuec852382014-02-14 08:36:00 +0530333 if (list && list->outbuf && (list->retireFenceFd < 0) ) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800334 // SF assumes HWC waits for the acquire fence and returns a new fence
335 // that signals when we're done. Since we don't wait, and also don't
336 // touch the buffer, we can just handle the acquire fence back to SF
337 // as the retire fence.
338 list->retireFenceFd = list->outbufAcquireFenceFd;
339 }
340
341 return ret;
342}
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800343
344void HWCVirtualV4L2::pause(hwc_context_t* ctx, int dpy) {
345 {
346 Locker::Autolock _l(ctx->mDrawLock);
347 ctx->dpyAttr[dpy].isActive = true;
348 ctx->dpyAttr[dpy].isPause = true;
349 ctx->proc->invalidate(ctx->proc);
350 }
351 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
352 * 2 / 1000);
353 // At this point all the pipes used by External have been
354 // marked as UNSET.
355 {
356 Locker::Autolock _l(ctx->mDrawLock);
357 // Perform commit to unstage the pipes.
358 if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
359 ALOGE("%s: display commit fail! for %d dpy",
360 __FUNCTION__, dpy);
361 }
362 }
363 return;
364}
365
366void HWCVirtualV4L2::resume(hwc_context_t* ctx, int dpy){
367 //Treat Resume as Online event
368 //Since external didnt have any pipes, force primary to give up
369 //its pipes; we don't allow inter-mixer pipe transfers.
370 {
371 Locker::Autolock _l(ctx->mDrawLock);
372
373 // A dynamic resolution change (DRC) can be made for a WiFi
374 // display. In order to support the resolution change, we
375 // need to reconfigure the corresponding display attributes.
376 // Since DRC is only on WiFi display, we only need to call
377 // configure() on the VirtualDisplay device.
378 //TODO: clean up
379 if(dpy == HWC_DISPLAY_VIRTUAL)
380 ctx->mVirtualDisplay->configure();
381
382 ctx->dpyAttr[dpy].isConfiguring = true;
383 ctx->dpyAttr[dpy].isActive = true;
384 ctx->proc->invalidate(ctx->proc);
385 }
386 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
387 * 2 / 1000);
388 //At this point external has all the pipes it would need.
389 {
390 Locker::Autolock _l(ctx->mDrawLock);
391 ctx->dpyAttr[dpy].isPause = false;
392 ctx->proc->invalidate(ctx->proc);
393 }
394 return;
395}