blob: a3a76126bca1ecf16cb7990f526cec64625fc747 [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 }
Manoj Kumar AVMfb472b02014-08-21 15:13:37 -070082 // signal synclock to indicate successful wfd teardown
Raj kamal59fea562014-04-01 16:52:19 +053083 ctx->mWfdSyncLock.lock();
84 ctx->mWfdSyncLock.signal();
85 ctx->mWfdSyncLock.unlock();
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080086 }
87}
88
89int HWCVirtualVDS::prepare(hwc_composer_device_1 *dev,
90 hwc_display_contents_1_t *list) {
91 ATRACE_CALL();
92 //XXX: Fix when framework support is added
93 hwc_context_t* ctx = (hwc_context_t*)(dev);
94 const int dpy = HWC_DISPLAY_VIRTUAL;
95
Tatenda Chipeperekwab0a9f9d2014-01-20 09:23:21 -080096 if (list && list->outbuf && list->numHwLayers > 0) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +053097 reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
98 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -080099 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
100 int fbWidth = 0, fbHeight = 0;
101 getLayerResolution(fbLayer, fbWidth, fbHeight);
102 ctx->dpyAttr[dpy].xres = fbWidth;
103 ctx->dpyAttr[dpy].yres = fbHeight;
104
105 if(ctx->dpyAttr[dpy].connected == false) {
106 ctx->dpyAttr[dpy].connected = true;
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800107 ctx->dpyAttr[dpy].isPause = false;
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800108 // We set the vsync period to the primary refresh rate, leaving
109 // it up to the consumer to decide how fast to consume frames.
110 ctx->dpyAttr[dpy].vsync_period
111 = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800112 init(ctx);
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800113 // XXX: for architectures with limited resources we would normally
114 // allow one padding round to free up resources but this breaks
115 // certain use cases.
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800116 }
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800117 if(!ctx->dpyAttr[dpy].isPause) {
118 ctx->dpyAttr[dpy].isConfiguring = false;
119 ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
120 private_handle_t *ohnd = (private_handle_t *)list->outbuf;
121 Writeback::getInstance()->configureDpyInfo(ohnd->width,
122 ohnd->height);
123 setListStats(ctx, list, dpy);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800124
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800125 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
126 const int fbZ = 0;
Saurabh Shahef19fe32014-04-22 15:31:58 -0700127 if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
128 {
129 ctx->mOverlay->clear(dpy);
130 ctx->mLayerRotMap[dpy]->clear();
131 }
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800132 }
133 } else {
134 /* Virtual Display is in Pause state.
135 * Mark all application layers as OVERLAY so that
136 * GPU will not compose.
137 */
Raj Kamale012e0e2014-05-28 23:45:19 +0530138 Writeback::getInstance(); //Ensure that WB is active during pause
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800139 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
140 hwc_layer_1_t *layer = &list->hwLayers[i];
141 layer->compositionType = HWC_OVERLAY;
142 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800143 }
144 }
145 return 0;
146}
147
148int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
149 ATRACE_CALL();
150 int ret = 0;
151 const int dpy = HWC_DISPLAY_VIRTUAL;
152
Tatenda Chipeperekwaf19f84d2014-01-17 12:43:29 -0800153 if (list && list->outbuf && list->numHwLayers > 0) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530154 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800155 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
156
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800157 if(ctx->dpyAttr[dpy].connected
158 && (!ctx->dpyAttr[dpy].isPause))
159 {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800160 private_handle_t *ohnd = (private_handle_t *)list->outbuf;
Tatenda Chipeperekwaa2fdebe2014-01-20 12:29:50 -0800161 int format = ohnd->format;
162 if (format == HAL_PIXEL_FORMAT_RGBA_8888)
163 format = HAL_PIXEL_FORMAT_RGBX_8888;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800164 Writeback::getInstance()->setOutputFormat(
Tatenda Chipeperekwaa2fdebe2014-01-20 12:29:50 -0800165 utils::getMdpFormat(format));
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800166
Manoj Kumar AVMfb472b02014-08-21 15:13:37 -0700167 // Configure WB secure mode based on output buffer handle
168 if(! Writeback::getInstance()->setSecure(isSecureBuffer(ohnd)))
169 {
170 ALOGE("Failed to set WB secure mode: %d for virtual display",
171 isSecureBuffer(ohnd));
172 return false;
Tatenda Chipeperekwa92961f82014-01-17 13:04:28 -0800173 }
174
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800175 int fd = -1; //FenceFD from the Copybit
176 hwc_sync(ctx, list, dpy, fd);
177
Tatenda Chipeperekwa523eac52014-05-29 14:58:39 -0700178 // Dump the layers for virtual
179 if(ctx->mHwcDebug[dpy])
180 ctx->mHwcDebug[dpy]->dumpLayers(list);
181
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800182 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
183 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
184 ret = -1;
185 }
Tatenda Chipeperekwad6a8d4b2014-01-14 18:31:20 -0800186 // We need an FB layer handle check to cater for this usecase:
187 // Video is playing in landscape on primary, then launch
188 // ScreenRecord app.
189 // In this scenario, the first VDS draw call will have HWC
190 // composition and VDS does nit involve GPU to get eglSwapBuffer
191 // to get valid fb handle.
192 if (fbLayer->handle && !ctx->mFBUpdate[dpy]->draw(ctx,
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800193 (private_handle_t *)fbLayer->handle)) {
194 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
195 ret = -1;
196 }
197
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530198 Writeback::getInstance()->queueBuffer(ohnd->fd,
199 (uint32_t)ohnd->offset);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800200 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
201 ALOGE("%s: display commit fail!", __FUNCTION__);
202 ret = -1;
203 }
204
Tatenda Chipeperekwa06af9cb2014-08-26 14:51:05 -0700205 if(sVDDumpEnabled) {
Tatenda Chipeperekwa523eac52014-05-29 14:58:39 -0700206 char bufferName[128];
207 // Dumping frame buffer
208 sync_wait(fbLayer->acquireFenceFd, 1000);
209 snprintf(bufferName, sizeof(bufferName), "vds.fb");
210 dumpBuffer((private_handle_t *)fbLayer->handle, bufferName);
211 // Dumping WB output for non-secure session
212 if(!isSecureBuffer(ohnd)) {
213 sync_wait(list->retireFenceFd, 1000);
214 snprintf(bufferName, sizeof(bufferName), "vds.wb");
215 dumpBuffer(ohnd, bufferName);
216 }
217 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800218 } else if(list->outbufAcquireFenceFd >= 0) {
219 //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
220 //which will make sure, the framework waits on it and closes it.
221 //The other way is to wait on outbufFenceFd ourselves, close it and
222 //set retireFenceFd to -1. Since we want hwc to be async, choosing
223 //the former.
224 //Also dup because, the closeAcquireFds() will close the outbufFence
225 list->retireFenceFd = dup(list->outbufAcquireFenceFd);
226 }
227 }
228
229 closeAcquireFds(list);
230 return ret;
231}
232
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800233void HWCVirtualVDS::pause(hwc_context_t* ctx, int dpy) {
234 {
235 Locker::Autolock _l(ctx->mDrawLock);
236 ctx->dpyAttr[dpy].isActive = true;
237 ctx->dpyAttr[dpy].isPause = true;
238 ctx->proc->invalidate(ctx->proc);
239 }
240 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
241 * 2 / 1000);
Raj Kamale012e0e2014-05-28 23:45:19 +0530242 // At this point all the pipes used by External have been
243 // marked as UNSET.
244 {
245 Locker::Autolock _l(ctx->mDrawLock);
246 // Perform commit to unstage the pipes.
247 if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
248 ALOGE("%s: display commit fail! for %d dpy",
249 __FUNCTION__, dpy);
250 }
Raj Kamaldf3d1d22014-05-30 21:23:27 +0530251 ctx->proc->invalidate(ctx->proc);
Raj Kamale012e0e2014-05-28 23:45:19 +0530252 }
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800253 return;
254}
255
256void HWCVirtualVDS::resume(hwc_context_t* ctx, int dpy) {
257 {
258 Locker::Autolock _l(ctx->mDrawLock);
259 ctx->dpyAttr[dpy].isConfiguring = true;
260 ctx->dpyAttr[dpy].isActive = true;
261 ctx->proc->invalidate(ctx->proc);
262 }
263 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
264 * 2 / 1000);
265 //At this point external has all the pipes it would need.
266 {
267 Locker::Autolock _l(ctx->mDrawLock);
268 ctx->dpyAttr[dpy].isPause = false;
269 ctx->proc->invalidate(ctx->proc);
270 }
271 return;
272}
273
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800274/* Implementation for HWCVirtualV4L2 class */
275
276int HWCVirtualV4L2::prepare(hwc_composer_device_1 *dev,
277 hwc_display_contents_1_t *list) {
278 ATRACE_CALL();
279
280 hwc_context_t* ctx = (hwc_context_t*)(dev);
281 const int dpy = HWC_DISPLAY_VIRTUAL;
282
283 if (LIKELY(list && list->numHwLayers > 1) &&
284 ctx->dpyAttr[dpy].isActive &&
Raj Kamal5ef25b82014-07-03 17:33:54 +0530285 ctx->dpyAttr[dpy].connected) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530286 reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800287 if(!ctx->dpyAttr[dpy].isPause) {
288 ctx->dpyAttr[dpy].isConfiguring = false;
289 setListStats(ctx, list, dpy);
290 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
291 const int fbZ = 0;
Saurabh Shahef19fe32014-04-22 15:31:58 -0700292 if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
293 {
294 ctx->mOverlay->clear(dpy);
295 ctx->mLayerRotMap[dpy]->clear();
296 }
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800297 }
298 } else {
299 /* Virtual Display is in Pause state.
300 * Mark all application layers as OVERLAY so that
301 * GPU will not compose.
302 */
303 for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
304 hwc_layer_1_t *layer = &list->hwLayers[i];
305 layer->compositionType = HWC_OVERLAY;
306 }
307 }
308 }
309 return 0;
310}
311
312int HWCVirtualV4L2::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
313 ATRACE_CALL();
314 int ret = 0;
315
316 const int dpy = HWC_DISPLAY_VIRTUAL;
317
318 if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
319 ctx->dpyAttr[dpy].connected &&
Raj Kamal5ef25b82014-07-03 17:33:54 +0530320 !ctx->dpyAttr[dpy].isPause) {
Praveena Pachipulusud9443c72014-02-17 10:42:28 +0530321 uint32_t last = (uint32_t)list->numHwLayers - 1;
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800322 hwc_layer_1_t *fbLayer = &list->hwLayers[last];
323 int fd = -1; //FenceFD from the Copybit(valid in async mode)
324 bool copybitDone = false;
325 if(ctx->mCopyBit[dpy])
326 copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
327
328 if(list->numHwLayers > 1)
329 hwc_sync(ctx, list, dpy, fd);
330
331 // Dump the layers for virtual
332 if(ctx->mHwcDebug[dpy])
333 ctx->mHwcDebug[dpy]->dumpLayers(list);
334
335 if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
336 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
337 ret = -1;
338 }
339
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800340 private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
Ramkumar Radhakrishnan3d863772014-08-12 16:49:03 -0700341 if(copybitDone) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800342 hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
343 }
344
Ramkumar Radhakrishnan3d863772014-08-12 16:49:03 -0700345 if(hnd) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800346 if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
347 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
348 ret = -1;
349 }
350 }
351
352 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
353 ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
354 ret = -1;
355 }
356 }
357
358 closeAcquireFds(list);
359
Baldev Sahuec852382014-02-14 08:36:00 +0530360 if (list && list->outbuf && (list->retireFenceFd < 0) ) {
Ramkumar Radhakrishnan8bb48d32013-12-30 23:11:27 -0800361 // SF assumes HWC waits for the acquire fence and returns a new fence
362 // that signals when we're done. Since we don't wait, and also don't
363 // touch the buffer, we can just handle the acquire fence back to SF
364 // as the retire fence.
365 list->retireFenceFd = list->outbufAcquireFenceFd;
366 }
367
368 return ret;
369}
Tatenda Chipeperekwa8f1b9d72014-02-11 16:20:50 -0800370
371void HWCVirtualV4L2::pause(hwc_context_t* ctx, int dpy) {
372 {
373 Locker::Autolock _l(ctx->mDrawLock);
374 ctx->dpyAttr[dpy].isActive = true;
375 ctx->dpyAttr[dpy].isPause = true;
376 ctx->proc->invalidate(ctx->proc);
377 }
378 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
379 * 2 / 1000);
380 // At this point all the pipes used by External have been
381 // marked as UNSET.
382 {
383 Locker::Autolock _l(ctx->mDrawLock);
384 // Perform commit to unstage the pipes.
385 if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
386 ALOGE("%s: display commit fail! for %d dpy",
387 __FUNCTION__, dpy);
388 }
389 }
390 return;
391}
392
393void HWCVirtualV4L2::resume(hwc_context_t* ctx, int dpy){
394 //Treat Resume as Online event
395 //Since external didnt have any pipes, force primary to give up
396 //its pipes; we don't allow inter-mixer pipe transfers.
397 {
398 Locker::Autolock _l(ctx->mDrawLock);
399
400 // A dynamic resolution change (DRC) can be made for a WiFi
401 // display. In order to support the resolution change, we
402 // need to reconfigure the corresponding display attributes.
403 // Since DRC is only on WiFi display, we only need to call
404 // configure() on the VirtualDisplay device.
405 //TODO: clean up
406 if(dpy == HWC_DISPLAY_VIRTUAL)
407 ctx->mVirtualDisplay->configure();
408
409 ctx->dpyAttr[dpy].isConfiguring = true;
410 ctx->dpyAttr[dpy].isActive = true;
411 ctx->proc->invalidate(ctx->proc);
412 }
413 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
414 * 2 / 1000);
415 //At this point external has all the pipes it would need.
416 {
417 Locker::Autolock _l(ctx->mDrawLock);
418 ctx->dpyAttr[dpy].isPause = false;
419 ctx->proc->invalidate(ctx->proc);
420 }
421 return;
422}