1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 * Copyright (C) 2012, The Linux Foundation All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <sys/ioctl.h>
19 #include <EGL/egl.h>
20 #include <cutils/properties.h>
21 #include <gralloc_priv.h>
22 #include <fb_priv.h>
23 #include <overlay.h>
24 #include "hwc_utils.h"
25 #include "hwc_mdpcomp.h"
26 #include "mdp_version.h"
27 #include "external.h"
28 #include "QService.h"
29
30 namespace qhwc {
31
32 // Opens Framebuffer device
openFramebufferDevice(hwc_context_t * ctx)33 static void openFramebufferDevice(hwc_context_t *ctx)
34 {
35 hw_module_t const *module;
36 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
37 framebuffer_open(module, &(ctx->mFbDev));
38 private_module_t* m = reinterpret_cast<private_module_t*>(
39 ctx->mFbDev->common.module);
40 //xres, yres may not be 32 aligned
41 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].stride = m->finfo.line_length /
42 (m->info.xres/8);
43 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres = m->info.xres;
44 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres = m->info.yres;
45 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = ctx->mFbDev->xdpi;
46 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ctx->mFbDev->ydpi;
47 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period =
48 1000000000l / ctx->mFbDev->fps;
49 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = openFb(HWC_DISPLAY_PRIMARY);
50 }
51 }
52
initContext(hwc_context_t * ctx)53 void initContext(hwc_context_t *ctx)
54 {
55 openFramebufferDevice(ctx);
56 overlay::Overlay::initOverlay();
57 ctx->mOverlay = overlay::Overlay::getInstance();
58 ctx->mQService = qService::QService::getInstance(ctx);
59 ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion();
60 ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
61 ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
62 ctx->mExtDisplay = new ExternalDisplay(ctx);
63 for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++)
64 ctx->mLayerCache[i] = new LayerCache();
65 MDPComp::init(ctx);
66
67 pthread_mutex_init(&(ctx->vstate.lock), NULL);
68 pthread_cond_init(&(ctx->vstate.cond), NULL);
69 ctx->vstate.enable = false;
70
71 ALOGI("Initializing Qualcomm Hardware Composer");
72 ALOGI("MDP version: %d", ctx->mMDP.version);
73 }
74
closeContext(hwc_context_t * ctx)75 void closeContext(hwc_context_t *ctx)
76 {
77 if(ctx->mOverlay) {
78 delete ctx->mOverlay;
79 ctx->mOverlay = NULL;
80 }
81
82 if(ctx->mFbDev) {
83 framebuffer_close(ctx->mFbDev);
84 ctx->mFbDev = NULL;
85 close(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd);
86 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = -1;
87 }
88
89 if(ctx->mExtDisplay) {
90 delete ctx->mExtDisplay;
91 ctx->mExtDisplay = NULL;
92 }
93
94 pthread_mutex_destroy(&(ctx->vstate.lock));
95 pthread_cond_destroy(&(ctx->vstate.cond));
96
97 }
98
dumpLayer(hwc_layer_1_t const * l)99 void dumpLayer(hwc_layer_1_t const* l)
100 {
101 ALOGD("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, {%d,%d,%d,%d}"
102 ", {%d,%d,%d,%d}",
103 l->compositionType, l->flags, l->handle, l->transform, l->blending,
104 l->sourceCrop.left,
105 l->sourceCrop.top,
106 l->sourceCrop.right,
107 l->sourceCrop.bottom,
108 l->displayFrame.left,
109 l->displayFrame.top,
110 l->displayFrame.right,
111 l->displayFrame.bottom);
112 }
113
isAlphaScaled(hwc_layer_1_t const * layer)114 static inline bool isAlphaScaled(hwc_layer_1_t const* layer) {
115 int dst_w, dst_h, src_w, src_h;
116
117 hwc_rect_t displayFrame = layer->displayFrame;
118 hwc_rect_t sourceCrop = layer->sourceCrop;
119
120 dst_w = displayFrame.right - displayFrame.left;
121 dst_h = displayFrame.bottom - displayFrame.top;
122
123 src_w = sourceCrop.right - sourceCrop.left;
124 src_h = sourceCrop.bottom - sourceCrop.top;
125
126 if(((src_w != dst_w) || (src_h != dst_h))) {
127 if(layer->blending != HWC_BLENDING_NONE)
128 return true;
129 }
130 return false;
131 }
132
setListStats(hwc_context_t * ctx,const hwc_display_contents_1_t * list,int dpy)133 void setListStats(hwc_context_t *ctx,
134 const hwc_display_contents_1_t *list, int dpy) {
135
136 ctx->listStats[dpy].numAppLayers = list->numHwLayers - 1;
137 ctx->listStats[dpy].fbLayerIndex = list->numHwLayers - 1;
138 ctx->listStats[dpy].yuvCount = 0;
139 ctx->listStats[dpy].yuvIndex = -1;
140 ctx->listStats[dpy].skipCount = 0;
141 ctx->listStats[dpy].needsAlphaScale = false;
142
143 for (size_t i = 0; i < list->numHwLayers; i++) {
144 hwc_layer_1_t const* layer = &list->hwLayers[i];
145 private_handle_t *hnd = (private_handle_t *)layer->handle;
146
147 if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
148 continue;
149 //We disregard FB being skip for now! so the else if
150 } else if (isSkipLayer(&list->hwLayers[i])) {
151 ctx->listStats[dpy].skipCount++;
152 }
153
154 if(!ctx->listStats[dpy].needsAlphaScale)
155 ctx->listStats[dpy].needsAlphaScale = isAlphaScaled(layer);
156
157 if (UNLIKELY(isYuvBuffer(hnd))) {
158 ctx->listStats[dpy].yuvCount++;
159 ctx->listStats[dpy].yuvIndex = i;
160 }
161 }
162 }
163
164
calc_cut(float & leftCutRatio,float & topCutRatio,float & rightCutRatio,float & bottomCutRatio,int orient)165 static inline void calc_cut(float& leftCutRatio, float& topCutRatio,
166 float& rightCutRatio, float& bottomCutRatio, int orient) {
167 if(orient & HAL_TRANSFORM_FLIP_H) {
168 swap(leftCutRatio, rightCutRatio);
169 }
170 if(orient & HAL_TRANSFORM_FLIP_V) {
171 swap(topCutRatio, bottomCutRatio);
172 }
173 if(orient & HAL_TRANSFORM_ROT_90) {
174 //Anti clock swapping
175 float tmpCutRatio = leftCutRatio;
176 leftCutRatio = topCutRatio;
177 topCutRatio = rightCutRatio;
178 rightCutRatio = bottomCutRatio;
179 bottomCutRatio = tmpCutRatio;
180 }
181 }
182
isSecuring(hwc_context_t * ctx)183 bool isSecuring(hwc_context_t* ctx) {
184 if((ctx->mMDP.version < qdutils::MDSS_V5) &&
185 (ctx->mMDP.version > qdutils::MDP_V3_0) &&
186 ctx->mSecuring) {
187 return true;
188 }
189 return false;
190 }
191
192
193 //Crops source buffer against destination and FB boundaries
calculate_crop_rects(hwc_rect_t & crop,hwc_rect_t & dst,const int fbWidth,const int fbHeight,int orient)194 void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
195 const int fbWidth, const int fbHeight, int orient) {
196 int& crop_l = crop.left;
197 int& crop_t = crop.top;
198 int& crop_r = crop.right;
199 int& crop_b = crop.bottom;
200 int crop_w = crop.right - crop.left;
201 int crop_h = crop.bottom - crop.top;
202
203 int& dst_l = dst.left;
204 int& dst_t = dst.top;
205 int& dst_r = dst.right;
206 int& dst_b = dst.bottom;
207 int dst_w = abs(dst.right - dst.left);
208 int dst_h = abs(dst.bottom - dst.top);
209
210 float leftCutRatio = 0.0f, rightCutRatio = 0.0f, topCutRatio = 0.0f,
211 bottomCutRatio = 0.0f;
212
213 if(dst_l < 0) {
214 leftCutRatio = (float)(0.0f - dst_l) / (float)dst_w;
215 dst_l = 0;
216 }
217 if(dst_r > fbWidth) {
218 rightCutRatio = (float)(dst_r - fbWidth) / (float)dst_w;
219 dst_r = fbWidth;
220 }
221 if(dst_t < 0) {
222 topCutRatio = (float)(0 - dst_t) / (float)dst_h;
223 dst_t = 0;
224 }
225 if(dst_b > fbHeight) {
226 bottomCutRatio = (float)(dst_b - fbHeight) / (float)dst_h;
227 dst_b = fbHeight;
228 }
229
230 calc_cut(leftCutRatio, topCutRatio, rightCutRatio, bottomCutRatio, orient);
231 crop_l += crop_w * leftCutRatio;
232 crop_t += crop_h * topCutRatio;
233 crop_r -= crop_w * rightCutRatio;
234 crop_b -= crop_h * bottomCutRatio;
235 }
236
isExternalActive(hwc_context_t * ctx)237 bool isExternalActive(hwc_context_t* ctx) {
238 return ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive;
239 }
240
hwc_sync(hwc_context_t * ctx,hwc_display_contents_1_t * list,int dpy)241 int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy) {
242 int ret = 0;
243 #ifdef USE_FENCE_SYNC
244 struct mdp_buf_sync data;
245 int acquireFd[MAX_NUM_LAYERS];
246 int count = 0;
247 int releaseFd = -1;
248 int fbFd = -1;
249 data.flags = MDP_BUF_SYNC_FLAG_WAIT;
250 data.acq_fen_fd = acquireFd;
251 data.rel_fen_fd = &releaseFd;
252 //Accumulate acquireFenceFds
253 for(uint32_t i = 0; i < list->numHwLayers; i++) {
254 if((list->hwLayers[i].compositionType == HWC_OVERLAY ||
255 list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) &&
256 list->hwLayers[i].acquireFenceFd != -1 ){
257 acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
258 }
259 }
260
261 data.acq_fen_fd_cnt = count;
262 fbFd = ctx->dpyAttr[dpy].fd;
263
264 //Waits for acquire fences, returns a release fence
265 ret = ioctl(fbFd, MSMFB_BUFFER_SYNC, &data);
266 if(ret < 0) {
267 ALOGE("ioctl MSMFB_BUFFER_SYNC failed, err=%s",
268 strerror(errno));
269 }
270
271 for(uint32_t i = 0; i < list->numHwLayers; i++) {
272 if((list->hwLayers[i].compositionType == HWC_OVERLAY ||
273 list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET)) {
274 //Close the acquireFenceFds
275 if(list->hwLayers[i].acquireFenceFd > 0) {
276 close(list->hwLayers[i].acquireFenceFd);
277 list->hwLayers[i].acquireFenceFd = -1;
278 }
279 //Populate releaseFenceFds.
280 list->hwLayers[i].releaseFenceFd = dup(releaseFd);
281 }
282 }
283 list->retireFenceFd = releaseFd;
284 #endif
285 return ret;
286 }
287
resetLayerCache(int num)288 void LayerCache::resetLayerCache(int num) {
289 for(uint32_t i = 0; i < MAX_NUM_LAYERS; i++) {
290 hnd[i] = NULL;
291 }
292 numHwLayers = num;
293 }
294
updateLayerCache(hwc_display_contents_1_t * list)295 void LayerCache::updateLayerCache(hwc_display_contents_1_t* list) {
296
297 int numFbLayers = 0;
298 int numCacheableLayers = 0;
299
300 canUseLayerCache = false;
301 //Bail if geometry changed or num of layers changed
302 if(list->flags & HWC_GEOMETRY_CHANGED ||
303 list->numHwLayers != numHwLayers ) {
304 resetLayerCache(list->numHwLayers);
305 return;
306 }
307
308 for(uint32_t i = 0; i < list->numHwLayers; i++) {
309 //Bail on skip layers
310 if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
311 resetLayerCache(list->numHwLayers);
312 return;
313 }
314
315 if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER) {
316 numFbLayers++;
317 if(hnd[i] == NULL) {
318 hnd[i] = list->hwLayers[i].handle;
319 } else if (hnd[i] ==
320 list->hwLayers[i].handle) {
321 numCacheableLayers++;
322 } else {
323 hnd[i] = NULL;
324 return;
325 }
326 } else {
327 hnd[i] = NULL;
328 }
329 }
330 if(numFbLayers == numCacheableLayers)
331 canUseLayerCache = true;
332
333 //XXX: The marking part is separate, if MDP comp wants
334 // to use it in the future. Right now getting MDP comp
335 // to use this is more trouble than it is worth.
336 markCachedLayersAsOverlay(list);
337 }
338
markCachedLayersAsOverlay(hwc_display_contents_1_t * list)339 void LayerCache::markCachedLayersAsOverlay(hwc_display_contents_1_t* list) {
340 //This optimization only works if ALL the layer handles
341 //that were on the framebuffer didn't change.
342 if(canUseLayerCache){
343 for(uint32_t i = 0; i < list->numHwLayers; i++) {
344 if (list->hwLayers[i].handle &&
345 list->hwLayers[i].handle == hnd[i] &&
346 list->hwLayers[i].compositionType != HWC_FRAMEBUFFER_TARGET)
347 {
348 list->hwLayers[i].compositionType = HWC_OVERLAY;
349 }
350 }
351 }
352
353 }
354
355 };//namespace
356