blob: d060439af8ee21c3cae0226cfcf1ce55bcd94b60 [file] [log] [blame]
Iliyan Malchev202a77d2012-06-11 14:41:12 -07001/*
2 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
3
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of Code Aurora Forum, Inc. nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <cutils/log.h>
31#include <cutils/memory.h>
32#include <qcom_ui.h>
Naseer Ahmed29a26812012-06-14 00:56:20 -070033#include <utils/comptype.h>
Iliyan Malchev202a77d2012-06-11 14:41:12 -070034#include <gralloc_priv.h>
35#include <alloc_controller.h>
36#include <memalloc.h>
37#include <errno.h>
38#include <EGL/eglext.h>
39#include <sys/stat.h>
40#include <SkBitmap.h>
41#include <SkImageEncoder.h>
42#include <Transform.h>
43
Iliyan Malchev202a77d2012-06-11 14:41:12 -070044using gralloc::IMemAlloc;
45using gralloc::IonController;
46using gralloc::alloc_data;
47using android::sp;
Iliyan Malchev202a77d2012-06-11 14:41:12 -070048namespace {
49
Naseer Ahmed29a26812012-06-14 00:56:20 -070050static android::sp<gralloc::IAllocController> sAlloc = 0;
Iliyan Malchev202a77d2012-06-11 14:41:12 -070051
Naseer Ahmed29a26812012-06-14 00:56:20 -070052int reallocate_memory(native_handle_t *buffer_handle, int mReqSize, int usage)
53{
54 int ret = 0;
Iliyan Malchev202a77d2012-06-11 14:41:12 -070055
56#ifndef NON_QCOM_TARGET
Naseer Ahmed29a26812012-06-14 00:56:20 -070057 if (sAlloc == 0) {
58 sAlloc = gralloc::IAllocController::getInstance(true);
Iliyan Malchev202a77d2012-06-11 14:41:12 -070059 }
Naseer Ahmed29a26812012-06-14 00:56:20 -070060 if (sAlloc == 0) {
61 LOGE("sAlloc is still NULL");
62 return -EINVAL;
63 }
64
65 // Dealloc the old memory
66 private_handle_t *hnd = (private_handle_t *)buffer_handle;
67 sp<IMemAlloc> memalloc = sAlloc->getAllocator(hnd->flags);
68 ret = memalloc->free_buffer((void*)hnd->base, hnd->size, hnd->offset, hnd->fd);
69
70 if (ret) {
71 LOGE("%s: free_buffer failed", __FUNCTION__);
72 return -1;
73 }
74
75 // Realloc new memory
76 alloc_data data;
77 data.base = 0;
78 data.fd = -1;
79 data.offset = 0;
80 data.size = mReqSize;
81 data.align = getpagesize();
82 data.uncached = true;
83 int allocFlags = usage;
84
85 switch (hnd->format) {
86 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
87 case (HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED^HAL_PIXEL_FORMAT_INTERLACE): {
88 data.align = 8192;
89 } break;
90 default: break;
91 }
92 ret = sAlloc->allocate(data, allocFlags, 0);
93 if (ret == 0) {
94 hnd->fd = data.fd;
95 hnd->base = (int)data.base;
96 hnd->offset = data.offset;
97 hnd->size = data.size;
98 } else {
99 LOGE("%s: allocate failed", __FUNCTION__);
100 return -EINVAL;
101 }
102#endif
103 return ret;
104}
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700105}; // ANONYNMOUS NAMESPACE
106
107/*
108 * Gets the number of arguments required for this operation.
109 *
110 * @param: operation whose argument count is required.
111 *
112 * @return -EINVAL if the operation is invalid.
113 */
114int getNumberOfArgsForOperation(int operation) {
115 int num_args = -EINVAL;
116 switch(operation) {
117 case NATIVE_WINDOW_SET_BUFFERS_SIZE:
118 num_args = 1;
119 break;
120 case NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY:
121 num_args = 3;
122 break;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700123 case NATIVE_WINDOW_SET_PIXEL_ASPECT_RATIO:
124 num_args = 2;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700125 break;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700126 default: LOGE("%s: invalid operation(0x%x)", __FUNCTION__, operation);
127 break;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700128 };
129 return num_args;
130}
131
132/*
133 * Checks if the format is supported by the GPU.
134 *
135 * @param: format to check
136 *
137 * @return true if the format is supported by the GPU.
138 */
139bool isGPUSupportedFormat(int format) {
140 if (format == HAL_PIXEL_FORMAT_YV12) {
141 // We check the YV12 formats, since some Qcom specific formats
142 // could have the bits set.
143 return true;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700144 } else if ((format == HAL_PIXEL_FORMAT_RGB_888) ||
145 (format == HAL_PIXEL_FORMAT_YCrCb_422_SP) ||
146 (format == HAL_PIXEL_FORMAT_YCbCr_422_SP)){
147 return false;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700148 } else if (format & INTERLACE_MASK) {
149 // Interlaced content
150 return false;
151 } else if (format & S3D_FORMAT_MASK) {
152 // S3D Formats are not supported by the GPU
Naseer Ahmed29a26812012-06-14 00:56:20 -0700153 return false;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700154 }
155 return true;
156}
157
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700158/*
159 * Function to check if the allocated buffer is of the correct size.
160 * Reallocate the buffer with the correct size, if the size doesn't
161 * match
162 *
163 * @param: handle of the allocated buffer
164 * @param: requested size for the buffer
165 * @param: usage flags
166 *
167 * return 0 on success
168 */
169int checkBuffer(native_handle_t *buffer_handle, int size, int usage)
170{
171 // If the client hasn't set a size, return
172 if (0 >= size) {
173 return 0;
174 }
175
176 // Validate the handle
177 if (private_handle_t::validate(buffer_handle)) {
Naseer Ahmed29a26812012-06-14 00:56:20 -0700178 LOGE("%s: handle is invalid", __FUNCTION__);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700179 return -EINVAL;
180 }
181
182 // Obtain the private_handle from the native handle
183 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
184 if (hnd->size != size) {
185 return reallocate_memory(hnd, size, usage);
186 }
187 return 0;
188}
189
190/*
191 * Checks if memory needs to be reallocated for this buffer.
192 *
193 * @param: Geometry of the current buffer.
194 * @param: Required Geometry.
195 * @param: Geometry of the updated buffer.
196 *
197 * @return True if a memory reallocation is required.
198 */
199bool needNewBuffer(const qBufGeometry currentGeometry,
200 const qBufGeometry requiredGeometry,
201 const qBufGeometry updatedGeometry)
202{
203 // If the current buffer info matches the updated info,
204 // we do not require any memory allocation.
205 if (updatedGeometry.width && updatedGeometry.height &&
206 updatedGeometry.format) {
207 return false;
208 }
209 if (currentGeometry.width != requiredGeometry.width ||
210 currentGeometry.height != requiredGeometry.height ||
211 currentGeometry.format != requiredGeometry.format) {
212 // Current and required geometry do not match. Allocation
213 // required.
214 return true;
215 }
216 return false;
217}
218
219/*
220 * Update the geometry of this buffer without reallocation.
221 *
222 * @param: buffer whose geometry needs to be updated.
223 * @param: Updated width
224 * @param: Updated height
225 * @param: Updated format
226 */
227int updateBufferGeometry(sp<GraphicBuffer> buffer, const qBufGeometry updatedGeometry)
228{
229 if (buffer == 0) {
Naseer Ahmed29a26812012-06-14 00:56:20 -0700230 LOGE("%s: graphic buffer is NULL", __FUNCTION__);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700231 return -EINVAL;
232 }
233
234 if (!updatedGeometry.width || !updatedGeometry.height ||
235 !updatedGeometry.format) {
236 // No update required. Return.
237 return 0;
238 }
239 if (buffer->width == updatedGeometry.width &&
240 buffer->height == updatedGeometry.height &&
241 buffer->format == updatedGeometry.format) {
242 // The buffer has already been updated. Return.
243 return 0;
244 }
245
246 // Validate the handle
247 if (private_handle_t::validate(buffer->handle)) {
Naseer Ahmed29a26812012-06-14 00:56:20 -0700248 LOGE("%s: handle is invalid", __FUNCTION__);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700249 return -EINVAL;
250 }
251 buffer->width = updatedGeometry.width;
252 buffer->height = updatedGeometry.height;
253 buffer->format = updatedGeometry.format;
254 private_handle_t *hnd = (private_handle_t*)(buffer->handle);
255 if (hnd) {
256 hnd->width = updatedGeometry.width;
257 hnd->height = updatedGeometry.height;
258 hnd->format = updatedGeometry.format;
259 } else {
Naseer Ahmed29a26812012-06-14 00:56:20 -0700260 LOGE("%s: hnd is NULL", __FUNCTION__);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700261 return -EINVAL;
262 }
263
264 return 0;
265}
266
267/* Update the S3D format of this buffer.
Naseer Ahmed29a26812012-06-14 00:56:20 -0700268 *
269 * @param: buffer whosei S3D format needs to be updated.
270 * @param: Updated buffer S3D format
271 */
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700272int updateBufferS3DFormat(sp<GraphicBuffer> buffer, const int s3dFormat)
273{
274 if (buffer == 0) {
Naseer Ahmed29a26812012-06-14 00:56:20 -0700275 LOGE("%s: graphic buffer is NULL", __FUNCTION__);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700276 return -EINVAL;
277 }
278
279 buffer->format |= s3dFormat;
280 return 0;
281}
282/*
283 * Updates the flags for the layer
284 *
285 * @param: Attribute
286 * @param: Identifies if the attribute was enabled or disabled.
287 *
288 * @return: -EINVAL if the attribute is invalid
289 */
290int updateLayerQcomFlags(eLayerAttrib attribute, bool enable, int& currentFlags)
291{
292 int ret = 0;
293 switch (attribute) {
294 case LAYER_UPDATE_STATUS: {
295 if (enable)
296 currentFlags |= LAYER_UPDATING;
297 else
298 currentFlags &= ~LAYER_UPDATING;
299 } break;
300 case LAYER_ASYNCHRONOUS_STATUS: {
301 if (enable)
302 currentFlags |= LAYER_ASYNCHRONOUS;
303 else
304 currentFlags &= ~LAYER_ASYNCHRONOUS;
305 } break;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700306 default: LOGE("%s: invalid attribute(0x%x)", __FUNCTION__, attribute);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700307 break;
308 }
309 return ret;
310}
311
312/*
313 * Gets the per frame HWC flags for this layer.
314 *
315 * @param: current hwcl flags
316 * @param: current layerFlags
317 *
318 * @return: the per frame flags.
319 */
320int getPerFrameFlags(int hwclFlags, int layerFlags) {
321 int flags = hwclFlags;
322 if (layerFlags & LAYER_UPDATING)
323 flags &= ~HWC_LAYER_NOT_UPDATING;
324 else
325 flags |= HWC_LAYER_NOT_UPDATING;
326
327 if (layerFlags & LAYER_ASYNCHRONOUS)
328 flags |= HWC_LAYER_ASYNCHRONOUS;
329 else
330 flags &= ~HWC_LAYER_ASYNCHRONOUS;
331
332 return flags;
333}
334
335
336/*
337 * Checks if FB is updated by this composition type
338 *
339 * @param: composition type
340 * @return: true if FB is updated, false if not
341 */
342
343bool isUpdatingFB(HWCCompositionType compositionType)
344{
345 switch(compositionType)
346 {
347 case HWC_USE_COPYBIT:
348 return true;
349 default:
Naseer Ahmed29a26812012-06-14 00:56:20 -0700350 LOGE("%s: invalid composition type(%d)", __FUNCTION__, compositionType);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700351 return false;
352 };
353}
354
355/*
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700356 * Clear Region implementation for C2D/MDP versions.
357 *
358 * @param: region to be cleared
359 * @param: EGL Display
360 * @param: EGL Surface
361 *
362 * @return 0 on success
363 */
364int qcomuiClearRegion(Region region, EGLDisplay dpy, EGLSurface sur)
365{
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700366 int ret = 0;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700367 int compositionType = QCCompositionType::getInstance().getCompositionType();
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700368
Naseer Ahmed29a26812012-06-14 00:56:20 -0700369 if (compositionType & COMPOSITION_TYPE_GPU ||
370 (compositionType == COMPOSITION_TYPE_DYN|COMPOSITION_TYPE_C2D))
371 {
372 // For GPU or DYN comp. with C2D, return an error, so that SF can use
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700373 // the GPU to draw the wormhole.
374 return -1;
375 }
376
377 android_native_buffer_t *renderBuffer = (android_native_buffer_t *)
Naseer Ahmed29a26812012-06-14 00:56:20 -0700378 eglGetRenderBufferANDROID(dpy, sur);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700379 if (!renderBuffer) {
Naseer Ahmed29a26812012-06-14 00:56:20 -0700380 LOGE("%s: eglGetRenderBufferANDROID returned NULL buffer",
381 __FUNCTION__);
382 return -1;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700383 }
384 private_handle_t *fbHandle = (private_handle_t *)renderBuffer->handle;
385 if(!fbHandle) {
Naseer Ahmed29a26812012-06-14 00:56:20 -0700386 LOGE("%s: Framebuffer handle is NULL", __FUNCTION__);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700387 return -1;
388 }
389
390 int bytesPerPixel = 4;
391 if (HAL_PIXEL_FORMAT_RGB_565 == fbHandle->format) {
392 bytesPerPixel = 2;
393 }
394
395 Region::const_iterator it = region.begin();
396 Region::const_iterator const end = region.end();
397 const int32_t stride = renderBuffer->stride*bytesPerPixel;
398 while (it != end) {
399 const Rect& r = *it++;
400 uint8_t* dst = (uint8_t*) fbHandle->base +
Naseer Ahmed29a26812012-06-14 00:56:20 -0700401 (r.left + r.top*renderBuffer->stride)*bytesPerPixel;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700402 int w = r.width()*bytesPerPixel;
403 int h = r.height();
404 do {
405 if(4 == bytesPerPixel)
406 android_memset32((uint32_t*)dst, 0, w);
407 else
408 android_memset16((uint16_t*)dst, 0, w);
409 dst += stride;
410 } while(--h);
411 }
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700412 return 0;
413}
414
415/*
416 * Handles the externalDisplay event
417 * HDMI has highest priority compared to WifiDisplay
Naseer Ahmed29a26812012-06-14 00:56:20 -0700418 * Based on the current and the new display type, decides the
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700419 * external display to be enabled
420 *
Naseer Ahmed29a26812012-06-14 00:56:20 -0700421 * @param: disp - external display type(wfd/hdmi)
422 * @param: value - external event(0/1)
423 * @param: currdispType - Current enabled external display Type
424 * @return: external display type to be enabled
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700425 *
426 */
Naseer Ahmed29a26812012-06-14 00:56:20 -0700427external_display_type handleEventHDMI(external_display_type disp, int value,
428 external_display_type currDispType)
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700429{
Naseer Ahmed29a26812012-06-14 00:56:20 -0700430 external_display_type retDispType = currDispType;
431 switch(disp) {
432 case EXT_TYPE_HDMI:
433 if(value)
434 retDispType = EXT_TYPE_HDMI;
435 else
436 retDispType = EXT_TYPE_NONE;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700437 break;
Naseer Ahmed29a26812012-06-14 00:56:20 -0700438 case EXT_TYPE_WIFI:
439 if(currDispType != EXT_TYPE_HDMI) {
440 if(value)
441 retDispType = EXT_TYPE_WIFI;
442 else
443 retDispType = EXT_TYPE_NONE;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700444 }
445 break;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700446 default:
Naseer Ahmed29a26812012-06-14 00:56:20 -0700447 LOGE("%s: Unknown External Display Type!!");
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700448 break;
449 }
Naseer Ahmed29a26812012-06-14 00:56:20 -0700450 return retDispType;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700451}
452
453// Using global variables for layer dumping since "property_set("debug.sf.dump",
454// property)" does not work.
455int sfdump_countlimit_raw = 0;
456int sfdump_counter_raw = 1;
457char sfdump_propstr_persist_raw[PROPERTY_VALUE_MAX] = "";
458char sfdumpdir_raw[256] = "";
459int sfdump_countlimit_png = 0;
460int sfdump_counter_png = 1;
461char sfdump_propstr_persist_png[PROPERTY_VALUE_MAX] = "";
462char sfdumpdir_png[256] = "";
463
464bool needToDumpLayers()
465{
466 bool bDumpLayer = false;
467 char sfdump_propstr[PROPERTY_VALUE_MAX];
468 time_t timenow;
469 tm sfdump_time;
470
471 time(&timenow);
472 localtime_r(&timenow, &sfdump_time);
473
474 if ((property_get("debug.sf.dump.png", sfdump_propstr, NULL) > 0) &&
Naseer Ahmed29a26812012-06-14 00:56:20 -0700475 (strncmp(sfdump_propstr, sfdump_propstr_persist_png,
476 PROPERTY_VALUE_MAX - 1))) {
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700477 // Strings exist & not equal implies it has changed, so trigger a dump
478 strncpy(sfdump_propstr_persist_png, sfdump_propstr,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700479 PROPERTY_VALUE_MAX - 1);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700480 sfdump_countlimit_png = atoi(sfdump_propstr);
481 sfdump_countlimit_png = (sfdump_countlimit_png < 0) ? 0:
Naseer Ahmed29a26812012-06-14 00:56:20 -0700482 (sfdump_countlimit_png >= LONG_MAX) ? (LONG_MAX - 1):
483 sfdump_countlimit_png;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700484 if (sfdump_countlimit_png) {
485 sprintf(sfdumpdir_png,"/data/sfdump.png%04d%02d%02d.%02d%02d%02d",
Naseer Ahmed29a26812012-06-14 00:56:20 -0700486 sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1,
487 sfdump_time.tm_mday, sfdump_time.tm_hour,
488 sfdump_time.tm_min, sfdump_time.tm_sec);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700489 if (0 == mkdir(sfdumpdir_png, 0777))
490 sfdump_counter_png = 0;
491 else
Naseer Ahmed29a26812012-06-14 00:56:20 -0700492 LOGE("sfdump: Error: %s. Failed to create sfdump directory"
493 ": %s", strerror(errno), sfdumpdir_png);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700494 }
495 }
496
497 if (sfdump_counter_png <= sfdump_countlimit_png)
498 sfdump_counter_png++;
499
500 if ((property_get("debug.sf.dump", sfdump_propstr, NULL) > 0) &&
Naseer Ahmed29a26812012-06-14 00:56:20 -0700501 (strncmp(sfdump_propstr, sfdump_propstr_persist_raw,
502 PROPERTY_VALUE_MAX - 1))) {
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700503 // Strings exist & not equal implies it has changed, so trigger a dump
504 strncpy(sfdump_propstr_persist_raw, sfdump_propstr,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700505 PROPERTY_VALUE_MAX - 1);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700506 sfdump_countlimit_raw = atoi(sfdump_propstr);
507 sfdump_countlimit_raw = (sfdump_countlimit_raw < 0) ? 0:
Naseer Ahmed29a26812012-06-14 00:56:20 -0700508 (sfdump_countlimit_raw >= LONG_MAX) ? (LONG_MAX - 1):
509 sfdump_countlimit_raw;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700510 if (sfdump_countlimit_raw) {
511 sprintf(sfdumpdir_raw,"/data/sfdump.raw%04d%02d%02d.%02d%02d%02d",
Naseer Ahmed29a26812012-06-14 00:56:20 -0700512 sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1,
513 sfdump_time.tm_mday, sfdump_time.tm_hour,
514 sfdump_time.tm_min, sfdump_time.tm_sec);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700515 if (0 == mkdir(sfdumpdir_raw, 0777))
516 sfdump_counter_raw = 0;
517 else
Naseer Ahmed29a26812012-06-14 00:56:20 -0700518 LOGE("sfdump: Error: %s. Failed to create sfdump directory"
519 ": %s", strerror(errno), sfdumpdir_raw);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700520 }
521 }
522
523 if (sfdump_counter_raw <= sfdump_countlimit_raw)
524 sfdump_counter_raw++;
525
526 bDumpLayer = (sfdump_countlimit_png || sfdump_countlimit_raw)? true : false;
527 return bDumpLayer;
528}
529
530inline void getHalPixelFormatStr(int format, char pixelformatstr[])
531{
532 if (!pixelformatstr)
533 return;
534
535 switch(format) {
Naseer Ahmed29a26812012-06-14 00:56:20 -0700536 case HAL_PIXEL_FORMAT_RGBA_8888:
537 strcpy(pixelformatstr, "RGBA_8888");
538 break;
539 case HAL_PIXEL_FORMAT_RGBX_8888:
540 strcpy(pixelformatstr, "RGBX_8888");
541 break;
542 case HAL_PIXEL_FORMAT_RGB_888:
543 strcpy(pixelformatstr, "RGB_888");
544 break;
545 case HAL_PIXEL_FORMAT_RGB_565:
546 strcpy(pixelformatstr, "RGB_565");
547 break;
548 case HAL_PIXEL_FORMAT_BGRA_8888:
549 strcpy(pixelformatstr, "BGRA_8888");
550 break;
551 case HAL_PIXEL_FORMAT_RGBA_5551:
552 strcpy(pixelformatstr, "RGBA_5551");
553 break;
554 case HAL_PIXEL_FORMAT_RGBA_4444:
555 strcpy(pixelformatstr, "RGBA_4444");
556 break;
557 case HAL_PIXEL_FORMAT_YV12:
558 strcpy(pixelformatstr, "YV12");
559 break;
560 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
561 strcpy(pixelformatstr, "YCbCr_422_SP_NV16");
562 break;
563 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
564 strcpy(pixelformatstr, "YCrCb_420_SP_NV21");
565 break;
566 case HAL_PIXEL_FORMAT_YCbCr_422_I:
567 strcpy(pixelformatstr, "YCbCr_422_I_YUY2");
568 break;
569 case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
570 strcpy(pixelformatstr, "NV12_ENCODEABLE");
571 break;
572 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
573 strcpy(pixelformatstr, "YCbCr_420_SP_TILED_TILE_4x2");
574 break;
575 case HAL_PIXEL_FORMAT_YCbCr_420_SP:
576 strcpy(pixelformatstr, "YCbCr_420_SP");
577 break;
578 case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
579 strcpy(pixelformatstr, "YCrCb_420_SP_ADRENO");
580 break;
581 case HAL_PIXEL_FORMAT_YCrCb_422_SP:
582 strcpy(pixelformatstr, "YCrCb_422_SP");
583 break;
584 case HAL_PIXEL_FORMAT_R_8:
585 strcpy(pixelformatstr, "R_8");
586 break;
587 case HAL_PIXEL_FORMAT_RG_88:
588 strcpy(pixelformatstr, "RG_88");
589 break;
590 case HAL_PIXEL_FORMAT_INTERLACE:
591 strcpy(pixelformatstr, "INTERLACE");
592 break;
593 default:
594 sprintf(pixelformatstr, "Unknown0x%X", format);
595 break;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700596 }
597}
598
599void dumpLayer(int moduleCompositionType, int listFlags, size_t layerIndex,
Naseer Ahmed29a26812012-06-14 00:56:20 -0700600 hwc_layer_t hwLayers[])
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700601{
602 char dumplogstr_png[128] = "";
603 char dumplogstr_raw[128] = "";
604 if (sfdump_counter_png <= sfdump_countlimit_png) {
605 sprintf(dumplogstr_png, "[png-dump-frame: %03d of %03d] ",
Naseer Ahmed29a26812012-06-14 00:56:20 -0700606 sfdump_counter_png, sfdump_countlimit_png);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700607 }
608 if (sfdump_counter_raw <= sfdump_countlimit_raw) {
609 sprintf(dumplogstr_raw, "[raw-dump-frame: %03d of %03d]",
Naseer Ahmed29a26812012-06-14 00:56:20 -0700610 sfdump_counter_raw, sfdump_countlimit_raw);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700611 }
612 if (NULL == hwLayers) {
Naseer Ahmed29a26812012-06-14 00:56:20 -0700613 LOGE("sfdump: Error.%s%sLayer[%d] No hwLayers to dump.",
614 dumplogstr_raw, dumplogstr_png, layerIndex);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700615 return;
616 }
617 hwc_layer *layer = &hwLayers[layerIndex];
618 hwc_rect_t sourceCrop = layer->sourceCrop;
619 hwc_rect_t displayFrame = layer->displayFrame;
620 private_handle_t *hnd = (private_handle_t *)layer->handle;
621 char pixelformatstr[32] = "None";
Naseer Ahmed29a26812012-06-14 00:56:20 -0700622 uint32_t transform = layer->transform & FINAL_TRANSFORM_MASK;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700623
624 if (hnd)
625 getHalPixelFormatStr(hnd->format, pixelformatstr);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700626
Naseer Ahmed29a26812012-06-14 00:56:20 -0700627 LOGE("sfdump: %s%s[%s]-Composition, Layer[%d] SrcBuff[%dx%d] "
628 "SrcCrop[%dl, %dt, %dr, %db] "
629 "DispFrame[%dl, %dt, %dr, %db] Composition-type = %s, Format = %s, "
630 "Orientation = %s, Flags = %s%s%s%s%s%s%s%s%s%s",
631 dumplogstr_raw, dumplogstr_png,
632 (moduleCompositionType == COMPOSITION_TYPE_GPU)? "GPU":
633 (moduleCompositionType == COMPOSITION_TYPE_MDP)? "MDP":
634 (moduleCompositionType == COMPOSITION_TYPE_C2D)? "C2D":
635 (moduleCompositionType == COMPOSITION_TYPE_CPU)? "CPU":
636 (moduleCompositionType == COMPOSITION_TYPE_DYN)? "DYN": "???",
637 layerIndex,
638 (hnd)? hnd->width : -1, (hnd)? hnd->height : -1,
639 sourceCrop.left, sourceCrop.top,
640 sourceCrop.right, sourceCrop.bottom,
641 displayFrame.left, displayFrame.top,
642 displayFrame.right, displayFrame.bottom,
643 (layer->compositionType == HWC_FRAMEBUFFER)? "Framebuffer (OpenGL ES)":
644 (layer->compositionType == HWC_OVERLAY)? "Overlay":
645 (layer->compositionType == HWC_USE_COPYBIT)? "Copybit": "???",
646 pixelformatstr,
647 (transform == Transform::ROT_0)? "ROT_0":
648 (transform == Transform::FLIP_H)? "FLIP_H":
649 (transform == Transform::FLIP_V)? "FLIP_V":
650 (transform == Transform::ROT_90)? "ROT_90":
651 (transform == Transform::ROT_180)? "ROT_180":
652 (transform == Transform::ROT_270)? "ROT_270":
653 (transform == Transform::ROT_INVALID)? "ROT_INVALID":"???",
654 (layer->flags == 0)? "[None]":"",
655 (layer->flags & HWC_SKIP_LAYER)? "[Skip layer]":"",
656 (layer->flags & HWC_LAYER_NOT_UPDATING)? "[Layer not updating]":"",
657 (layer->flags & HWC_COMP_BYPASS)? "[Bypass]":"",
658 (layer->flags & HWC_BYPASS_RESERVE_0)? "[Bypass Reserve 0]":"",
659 (layer->flags & HWC_BYPASS_RESERVE_1)? "[Bypass Reserve 1]":"",
660 (listFlags & HWC_GEOMETRY_CHANGED)? "[List: Geometry Changed]":"",
661 (listFlags & HWC_SKIP_COMPOSITION)? "[List: Skip Composition]":"");
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700662
Naseer Ahmed29a26812012-06-14 00:56:20 -0700663 if (NULL == hnd) {
664 LOGE("sfdump: %s%sLayer[%d] private-handle is invalid.",
665 dumplogstr_raw, dumplogstr_png, layerIndex);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700666 return;
667 }
668
Naseer Ahmed29a26812012-06-14 00:56:20 -0700669 if ((sfdump_counter_png <= sfdump_countlimit_png) && hnd->base) {
670 bool bResult = false;
671 char sfdumpfile_name[256];
672 SkBitmap *tempSkBmp = new SkBitmap();
673 SkBitmap::Config tempSkBmpConfig = SkBitmap::kNo_Config;
674 sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d.png", sfdumpdir_png,
675 sfdump_counter_png, layerIndex);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700676
Naseer Ahmed29a26812012-06-14 00:56:20 -0700677 switch (hnd->format) {
678 case HAL_PIXEL_FORMAT_RGBA_8888:
679 case HAL_PIXEL_FORMAT_RGBX_8888:
680 case HAL_PIXEL_FORMAT_BGRA_8888:
681 tempSkBmpConfig = SkBitmap::kARGB_8888_Config;
682 break;
683 case HAL_PIXEL_FORMAT_RGB_565:
684 case HAL_PIXEL_FORMAT_RGBA_5551:
685 case HAL_PIXEL_FORMAT_RGBA_4444:
686 tempSkBmpConfig = SkBitmap::kRGB_565_Config;
687 break;
688 case HAL_PIXEL_FORMAT_RGB_888:
689 default:
690 tempSkBmpConfig = SkBitmap::kNo_Config;
691 break;
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700692 }
Naseer Ahmed29a26812012-06-14 00:56:20 -0700693 if (SkBitmap::kNo_Config != tempSkBmpConfig) {
694 tempSkBmp->setConfig(tempSkBmpConfig, hnd->width, hnd->height);
695 tempSkBmp->setPixels((void*)hnd->base);
696 bResult = SkImageEncoder::EncodeFile(sfdumpfile_name,
697 *tempSkBmp, SkImageEncoder::kPNG_Type, 100);
698 LOGE("sfdump: %sDumped Layer[%d] to %s: %s", dumplogstr_png,
699 layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail");
700 }
701 else {
702 LOGE("sfdump: %sSkipping Layer[%d] dump: Unsupported layer "
703 "format %s for png encoder.", dumplogstr_png, layerIndex,
704 pixelformatstr);
705 }
706 delete tempSkBmp; // Calls SkBitmap::freePixels() internally.
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700707 }
708
Naseer Ahmed29a26812012-06-14 00:56:20 -0700709 if ((sfdump_counter_raw <= sfdump_countlimit_raw) && hnd->base) {
710 char sfdumpfile_name[256];
711 bool bResult = false;
712 sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d_%dx%d_%s.raw",
713 sfdumpdir_raw,
714 sfdump_counter_raw, layerIndex, hnd->width, hnd->height,
715 pixelformatstr);
716 FILE* fp = fopen(sfdumpfile_name, "w+");
717 if (fp != NULL) {
718 bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp);
719 fclose(fp);
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700720 }
Naseer Ahmed29a26812012-06-14 00:56:20 -0700721 LOGE("sfdump: %s Dumped Layer[%d] to %s: %s", dumplogstr_raw,
722 layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail");
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700723 }
Iliyan Malchev202a77d2012-06-11 14:41:12 -0700724}
Naseer Ahmed29a26812012-06-14 00:56:20 -0700725
726bool needsAspectRatio (int wRatio, int hRatio) {
727 return ((wRatio != DEFAULT_WIDTH_RATIO) || (hRatio != DEFAULT_HEIGHT_RATIO));
728}
729
730void applyPixelAspectRatio (int wRatio, int hRatio, int orientation, int maxWidth,
731 int maxHeight, Rect& visibleRect, GLfloat mVertices[][2]) {
732
733 if ((wRatio == 0) || (hRatio == 0))
734 return;
735
736 float wDelta = 0;
737 float hDelta = 0;
738 float aspectRatio;
739 float displayRatio;
740 float new_width, new_height;
741 float old_width = abs(visibleRect.right - visibleRect.left);
742 float old_height = abs(visibleRect.bottom - visibleRect.top);
743
744 if (orientation == Transform::ROT_INVALID) {
745 // During animation, no defined orientation, rely on mTransformedBounds
746 if (old_width >= old_height)
747 orientation = Transform::ROT_0;
748 else
749 orientation = Transform::ROT_90;
750 }
751
752 switch (orientation) {
753
754 case Transform::ROT_0:
755 case Transform::ROT_180:
756
757 // Calculated Aspect Ratio = Original Aspect Ratio x Pixel Aspect Ratio
758 aspectRatio = (old_width * wRatio) / (old_height * hRatio);
759 displayRatio = (float)maxWidth / (float)maxHeight;
760
761 if (aspectRatio >= displayRatio) {
762 new_height = old_width / aspectRatio;
763 if (new_height > maxHeight) {
764 new_height = maxHeight;
765 new_width = new_height * aspectRatio;
766 wDelta = (new_width - old_width) / 2;
767 }
768 hDelta = (new_height - old_height) / 2;
769 } else {
770 new_width = old_height * aspectRatio;
771 if (new_width > maxWidth) {
772 new_width = maxWidth;
773 new_height = new_width / aspectRatio;
774 hDelta = (new_height - old_height) / 2;
775 }
776 wDelta = (new_width - old_width) / 2;
777 }
778
779 if (hDelta != 0) {
780 visibleRect.top -= hDelta;
781 visibleRect.bottom += hDelta;
782
783 // Set mVertices for GPU fallback (During rotation)
784 if (orientation == Transform::ROT_0) {
785 mVertices[1][1] = mVertices[2][1] = visibleRect.top;
786 mVertices[0][1] = mVertices[3][1] = visibleRect.bottom;
787 } else {
788 mVertices[0][1] = mVertices[3][1] = visibleRect.top;
789 mVertices[1][1] = mVertices[2][1] = visibleRect.bottom;
790 }
791 }
792
793 if (wDelta != 0) {
794 visibleRect.left -= wDelta;
795 visibleRect.right += wDelta;
796
797 // Set mVertices for GPU fallback (During rotation)
798 mVertices[0][0] = mVertices[1][0] = visibleRect.left;
799 mVertices[2][0] = mVertices[3][0] = visibleRect.right;
800 }
801 break;
802
803 case Transform::ROT_90:
804 case Transform::ROT_270:
805
806 // Calculated Aspect Ratio = Original Aspect Ratio x Pixel Aspect Ratio
807 aspectRatio = (old_height * wRatio) / (old_width * hRatio);
808 displayRatio = (float)maxHeight / (float)maxWidth;
809
810 if (aspectRatio >= displayRatio) {
811 new_height = old_width * aspectRatio;
812 if (new_height > maxHeight) {
813 new_height = maxHeight;
814 new_width = new_height / aspectRatio;
815 wDelta = (new_width - old_width) / 2;
816 }
817 hDelta = (new_height - old_height) / 2;
818 } else {
819 new_width = old_height / aspectRatio;
820 if (new_width > maxWidth) {
821 new_width = maxWidth;
822 new_height = new_width * aspectRatio;
823 hDelta = (new_height - old_height) / 2;
824 }
825 wDelta = (new_width - old_width) / 2;
826 }
827
828 if (hDelta != 0) {
829 visibleRect.top -= hDelta;
830 visibleRect.bottom += hDelta;
831
832 // Set mVertices for GPU fallback (During rotation)
833 if (orientation == Transform::ROT_90) {
834 mVertices[2][1] = mVertices[3][1] = visibleRect.top;
835 mVertices[0][1] = mVertices[1][1] = visibleRect.bottom;
836 } else {
837 mVertices[0][1] = mVertices[1][1] = visibleRect.top;
838 mVertices[2][1] = mVertices[3][1] = visibleRect.bottom;
839 }
840 }
841
842 if (wDelta != 0) {
843 visibleRect.left -= wDelta;
844 visibleRect.right += wDelta;
845
846 // Set mVertices for GPU fallback (During rotation)
847 if (orientation == Transform::ROT_90) {
848 mVertices[1][0] = mVertices[2][0] = visibleRect.left;
849 mVertices[0][0] = mVertices[3][0] = visibleRect.right;
850 } else {
851 mVertices[0][0] = mVertices[3][0] = visibleRect.left;
852 mVertices[1][0] = mVertices[2][0] = visibleRect.right;
853 }
854 }
855 break;
856
857 default: // Handled above.
858 break;
859
860 }
861}
862
863