1 /*
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 <overlayWriteback.h>
25 #include "hwc_utils.h"
26 #include "hwc_fbupdate.h"
27 #include "hwc_mdpcomp.h"
28 #include "hwc_dump_layers.h"
29 #include "hwc_copybit.h"
30 #include "hwc_virtual.h"
31 #include "sync/sync.h"
32 #include <utils/Trace.h>
33 
34 #define HWCVIRTUAL_LOG 0
35 
36 using namespace qhwc;
37 using namespace overlay;
38 
39 bool HWCVirtualVDS::sVDDumpEnabled = false;
40 
init(hwc_context_t * ctx)41 void HWCVirtualVDS::init(hwc_context_t *ctx) {
42     const int dpy = HWC_DISPLAY_VIRTUAL;
43     mScalingWidth = 0, mScalingHeight = 0;
44     initCompositionResources(ctx, dpy);
45 
46     if(ctx->mFBUpdate[dpy])
47         ctx->mFBUpdate[dpy]->reset();
48     if(ctx->mMDPComp[dpy])
49         ctx->mMDPComp[dpy]->reset();
50 }
51 
destroy(hwc_context_t * ctx,size_t,hwc_display_contents_1_t ** displays)52 void HWCVirtualVDS::destroy(hwc_context_t *ctx, size_t /*numDisplays*/,
53                        hwc_display_contents_1_t** displays) {
54     int dpy = HWC_DISPLAY_VIRTUAL;
55 
56     //Cleanup virtual display objs, since there is no explicit disconnect
57     if(ctx->dpyAttr[dpy].connected && (displays[dpy] == NULL)) {
58         ctx->dpyAttr[dpy].connected = false;
59         ctx->dpyAttr[dpy].isPause = false;
60 
61         destroyCompositionResources(ctx, dpy);
62 
63         // signal synclock to indicate successful wfd teardown
64         ctx->mWfdSyncLock.lock();
65         ctx->mWfdSyncLock.signal();
66         ctx->mWfdSyncLock.unlock();
67     }
68 }
69 
prepare(hwc_composer_device_1 * dev,hwc_display_contents_1_t * list)70 int HWCVirtualVDS::prepare(hwc_composer_device_1 *dev,
71         hwc_display_contents_1_t *list) {
72     ATRACE_CALL();
73     //XXX: Fix when framework support is added
74     hwc_context_t* ctx = (hwc_context_t*)(dev);
75     const int dpy = HWC_DISPLAY_VIRTUAL;
76 
77     if (list && list->outbuf && list->numHwLayers > 0) {
78         reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
79         uint32_t last = (uint32_t)list->numHwLayers - 1;
80         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
81         int fbWidth = 0, fbHeight = 0;
82         getLayerResolution(fbLayer, fbWidth, fbHeight);
83         ctx->dpyAttr[dpy].xres = fbWidth;
84         ctx->dpyAttr[dpy].yres = fbHeight;
85 
86         if(ctx->dpyAttr[dpy].connected == false) {
87             ctx->dpyAttr[dpy].connected = true;
88             ctx->dpyAttr[dpy].isPause = false;
89             // We set the vsync period to the primary refresh rate, leaving
90             // it up to the consumer to decide how fast to consume frames.
91             ctx->dpyAttr[dpy].vsync_period
92                               = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period;
93             ctx->dpyAttr[dpy].fbformat = HAL_PIXEL_FORMAT_RGBA_8888;
94             init(ctx);
95             // Do one padding round for cases where primary has all pipes
96             // The virtual composition falls back to GPU in such cases.
97             ctx->isPaddingRound = true;
98         }
99         if(!ctx->dpyAttr[dpy].isPause) {
100             ctx->dpyAttr[dpy].isConfiguring = false;
101             ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
102             private_handle_t *ohnd = (private_handle_t *)list->outbuf;
103 
104             setMDPScalingMode(ctx, ohnd, dpy);
105 
106             mScalingWidth = getWidth(ohnd);
107             mScalingHeight = getHeight(ohnd);
108 
109             Writeback::getInstance()->configureDpyInfo(mScalingWidth,
110                                                         mScalingHeight);
111             setListStats(ctx, list, dpy);
112 
113             if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
114                 const int fbZ = 0;
115                 if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
116                 {
117                     ctx->mOverlay->clear(dpy);
118                     ctx->mLayerRotMap[dpy]->clear();
119                 }
120             }
121         } else {
122             /* Virtual Display is in Pause state.
123              * Mark all application layers as OVERLAY so that
124              * GPU will not compose.
125              */
126             Writeback::getInstance(); //Ensure that WB is active during pause
127             for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
128                 hwc_layer_1_t *layer = &list->hwLayers[i];
129                 layer->compositionType = HWC_OVERLAY;
130             }
131         }
132     }
133     return 0;
134 }
135 
set(hwc_context_t * ctx,hwc_display_contents_1_t * list)136 int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
137     ATRACE_CALL();
138     int ret = 0;
139     const int dpy = HWC_DISPLAY_VIRTUAL;
140 
141     if (list && list->outbuf && list->numHwLayers > 0) {
142         uint32_t last = (uint32_t)list->numHwLayers - 1;
143         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
144 
145         if(ctx->dpyAttr[dpy].connected
146                 && (!ctx->dpyAttr[dpy].isPause))
147         {
148             private_handle_t *ohnd = (private_handle_t *)list->outbuf;
149             int format = ohnd->format;
150             if (format == HAL_PIXEL_FORMAT_RGBA_8888)
151                 format = HAL_PIXEL_FORMAT_RGBX_8888;
152             Writeback::getInstance()->setOutputFormat(
153                                     utils::getMdpFormat(format));
154 
155             // Configure WB secure mode based on output buffer handle
156             if(! Writeback::getInstance()->setSecure(isSecureBuffer(ohnd)))
157             {
158                 ALOGE("Failed to set WB secure mode: %d for virtual display",
159                     isSecureBuffer(ohnd));
160                 return false;
161             }
162 
163             int fd = -1; //FenceFD from the Copybit
164             hwc_sync(ctx, list, dpy, fd);
165 
166             // Dump the layers for virtual
167             if(ctx->mHwcDebug[dpy])
168                 ctx->mHwcDebug[dpy]->dumpLayers(list);
169 
170             if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
171                 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
172                 ret = -1;
173             }
174             // We need an FB layer handle check to cater for this usecase:
175             // Video is playing in landscape on primary, then launch
176             // ScreenRecord app.
177             // In this scenario, the first VDS draw call will have HWC
178             // composition and VDS does nit involve GPU to get eglSwapBuffer
179             // to get valid fb handle.
180             if (fbLayer->handle && !ctx->mFBUpdate[dpy]->draw(ctx,
181                         (private_handle_t *)fbLayer->handle)) {
182                 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
183                 ret = -1;
184             }
185 
186             Writeback::getInstance()->queueBuffer(ohnd->fd,
187                                         (uint32_t)ohnd->offset);
188             if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
189                 ALOGE("%s: display commit fail!", __FUNCTION__);
190                 ret = -1;
191             }
192 
193             if(sVDDumpEnabled) {
194                 char bufferName[128];
195                 // Dumping frame buffer
196                 sync_wait(fbLayer->acquireFenceFd, 1000);
197                 snprintf(bufferName, sizeof(bufferName), "vds.fb");
198                 dumpBuffer((private_handle_t *)fbLayer->handle, bufferName);
199                 // Dumping WB output for non-secure session
200                 if(!isSecureBuffer(ohnd)) {
201                     sync_wait(list->retireFenceFd, 1000);
202                     snprintf(bufferName, sizeof(bufferName), "vds.wb");
203                     dumpBuffer(ohnd, bufferName);
204                 }
205             }
206         } else if(list->outbufAcquireFenceFd >= 0) {
207             //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
208             //which will make sure, the framework waits on it and closes it.
209             //The other way is to wait on outbufFenceFd ourselves, close it and
210             //set retireFenceFd to -1. Since we want hwc to be async, choosing
211             //the former.
212             //Also dup because, the closeAcquireFds() will close the outbufFence
213             list->retireFenceFd = dup(list->outbufAcquireFenceFd);
214         }
215     }
216 
217     closeAcquireFds(list);
218     return ret;
219 }
220 
221 /* We set scaling mode on the VD if the output handle width and height
222    differs from the virtual frame buffer width and height. */
setMDPScalingMode(hwc_context_t * ctx,private_handle_t * ohnd,int dpy)223 void HWCVirtualVDS::setMDPScalingMode(hwc_context_t* ctx,
224         private_handle_t* ohnd, int dpy) {
225     bool scalingMode = false;
226     int fbWidth = ctx->dpyAttr[dpy].xres;
227     int fbHeight =  ctx->dpyAttr[dpy].yres;
228     if((getWidth(ohnd) != fbWidth) || (getHeight(ohnd) != fbHeight)) {
229         scalingMode = true;
230     }
231     ctx->dpyAttr[dpy].mMDPScalingMode = scalingMode;
232 
233     ALOGD_IF(HWCVIRTUAL_LOG, "%s fb(%dx%d) outputBuffer(%dx%d) scalingMode=%d",
234             __FUNCTION__, fbWidth, fbHeight,
235             getWidth(ohnd), getHeight(ohnd), scalingMode);
236 }
237