blob: 80ce25dc3d94c1f10315e5e4f0ef5429d2064005 [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>
33#include <gralloc_priv.h>
34#include <alloc_controller.h>
35#include <memalloc.h>
36#include <errno.h>
37#include <EGL/eglext.h>
38#include <sys/stat.h>
39#include <SkBitmap.h>
40#include <SkImageEncoder.h>
41#include <Transform.h>
42
43#include <EGL/egl.h>
44#include <GLES2/gl2.h>
45#include <GLES2/gl2ext.h>
46
47using gralloc::IMemAlloc;
48using gralloc::IonController;
49using gralloc::alloc_data;
50using android::sp;
51
52static int sCompositionType = -1;
53
54namespace {
55
56 static android::sp<gralloc::IAllocController> sAlloc = 0;
57
58 int reallocate_memory(native_handle_t *buffer_handle, int mReqSize, int usage)
59 {
60 int ret = 0;
61
62#ifndef NON_QCOM_TARGET
63 if (sAlloc == 0) {
64 sAlloc = gralloc::IAllocController::getInstance(true);
65 }
66 if (sAlloc == 0) {
67 ALOGE("sAlloc is still NULL");
68 return -EINVAL;
69 }
70
71 // Dealloc the old memory
72 private_handle_t *hnd = (private_handle_t *)buffer_handle;
73 sp<IMemAlloc> memalloc = sAlloc->getAllocator(hnd->flags);
74 ret = memalloc->free_buffer((void*)hnd->base, hnd->size, hnd->offset, hnd->fd);
75
76 if (ret) {
77 ALOGE("%s: free_buffer failed", __FUNCTION__);
78 return -1;
79 }
80
81 // Realloc new memory
82 alloc_data data;
83 data.base = 0;
84 data.fd = -1;
85 data.offset = 0;
86 data.size = mReqSize;
87 data.align = getpagesize();
88 data.uncached = true;
89 int allocFlags = usage;
90
91 switch (hnd->format) {
92 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
93 case (HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED^HAL_PIXEL_FORMAT_INTERLACE): {
94 data.align = 8192;
95 } break;
96 default: break;
97 }
98 ret = sAlloc->allocate(data, allocFlags, 0);
99 if (ret == 0) {
100 hnd->fd = data.fd;
101 hnd->base = (int)data.base;
102 hnd->offset = data.offset;
103 hnd->size = data.size;
104 } else {
105 ALOGE("%s: allocate failed", __FUNCTION__);
106 return -EINVAL;
107 }
108#endif
109 return ret;
110 }
111}; // ANONYNMOUS NAMESPACE
112
113/*
114 * Gets the number of arguments required for this operation.
115 *
116 * @param: operation whose argument count is required.
117 *
118 * @return -EINVAL if the operation is invalid.
119 */
120int getNumberOfArgsForOperation(int operation) {
121 int num_args = -EINVAL;
122 switch(operation) {
123 case NATIVE_WINDOW_SET_BUFFERS_SIZE:
124 num_args = 1;
125 break;
126 case NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY:
127 num_args = 3;
128 break;
129 default: ALOGE("%s: invalid operation(0x%x)", __FUNCTION__, operation);
130 break;
131 };
132 return num_args;
133}
134
135/*
136 * Checks if the format is supported by the GPU.
137 *
138 * @param: format to check
139 *
140 * @return true if the format is supported by the GPU.
141 */
142bool isGPUSupportedFormat(int format) {
143 if (format == HAL_PIXEL_FORMAT_YV12) {
144 // We check the YV12 formats, since some Qcom specific formats
145 // could have the bits set.
146 return true;
147 } else if (format & INTERLACE_MASK) {
148 // Interlaced content
149 return false;
150 } else if (format & S3D_FORMAT_MASK) {
151 // S3D Formats are not supported by the GPU
152 return false;
153 }
154 return true;
155}
156
157/* decide the texture target dynamically, based on the pixel format*/
158
159int decideTextureTarget(int pixel_format)
160{
161
162 // Default the return value to GL_TEXTURE_EXTERAL_OES
163 int retVal = GL_TEXTURE_EXTERNAL_OES;
164
165 // Change texture target to TEXTURE_2D for RGB formats
166 switch (pixel_format) {
167
168 case HAL_PIXEL_FORMAT_RGBA_8888:
169 case HAL_PIXEL_FORMAT_RGBX_8888:
170 case HAL_PIXEL_FORMAT_RGB_888:
171 case HAL_PIXEL_FORMAT_RGB_565:
172 case HAL_PIXEL_FORMAT_BGRA_8888:
173 case HAL_PIXEL_FORMAT_RGBA_5551:
174 case HAL_PIXEL_FORMAT_RGBA_4444:
175 retVal = GL_TEXTURE_2D;
176 break;
177 default:
178 retVal = GL_TEXTURE_EXTERNAL_OES;
179 break;
180 }
181 return retVal;
182}
183
184/*
185 * Function to check if the allocated buffer is of the correct size.
186 * Reallocate the buffer with the correct size, if the size doesn't
187 * match
188 *
189 * @param: handle of the allocated buffer
190 * @param: requested size for the buffer
191 * @param: usage flags
192 *
193 * return 0 on success
194 */
195int checkBuffer(native_handle_t *buffer_handle, int size, int usage)
196{
197 // If the client hasn't set a size, return
198 if (0 >= size) {
199 return 0;
200 }
201
202 // Validate the handle
203 if (private_handle_t::validate(buffer_handle)) {
204 ALOGE("%s: handle is invalid", __FUNCTION__);
205 return -EINVAL;
206 }
207
208 // Obtain the private_handle from the native handle
209 private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
210 if (hnd->size != size) {
211 return reallocate_memory(hnd, size, usage);
212 }
213 return 0;
214}
215
216/*
217 * Checks if memory needs to be reallocated for this buffer.
218 *
219 * @param: Geometry of the current buffer.
220 * @param: Required Geometry.
221 * @param: Geometry of the updated buffer.
222 *
223 * @return True if a memory reallocation is required.
224 */
225bool needNewBuffer(const qBufGeometry currentGeometry,
226 const qBufGeometry requiredGeometry,
227 const qBufGeometry updatedGeometry)
228{
229 // If the current buffer info matches the updated info,
230 // we do not require any memory allocation.
231 if (updatedGeometry.width && updatedGeometry.height &&
232 updatedGeometry.format) {
233 return false;
234 }
235 if (currentGeometry.width != requiredGeometry.width ||
236 currentGeometry.height != requiredGeometry.height ||
237 currentGeometry.format != requiredGeometry.format) {
238 // Current and required geometry do not match. Allocation
239 // required.
240 return true;
241 }
242 return false;
243}
244
245/*
246 * Update the geometry of this buffer without reallocation.
247 *
248 * @param: buffer whose geometry needs to be updated.
249 * @param: Updated width
250 * @param: Updated height
251 * @param: Updated format
252 */
253int updateBufferGeometry(sp<GraphicBuffer> buffer, const qBufGeometry updatedGeometry)
254{
255 if (buffer == 0) {
256 ALOGE("%s: graphic buffer is NULL", __FUNCTION__);
257 return -EINVAL;
258 }
259
260 if (!updatedGeometry.width || !updatedGeometry.height ||
261 !updatedGeometry.format) {
262 // No update required. Return.
263 return 0;
264 }
265 if (buffer->width == updatedGeometry.width &&
266 buffer->height == updatedGeometry.height &&
267 buffer->format == updatedGeometry.format) {
268 // The buffer has already been updated. Return.
269 return 0;
270 }
271
272 // Validate the handle
273 if (private_handle_t::validate(buffer->handle)) {
274 ALOGE("%s: handle is invalid", __FUNCTION__);
275 return -EINVAL;
276 }
277 buffer->width = updatedGeometry.width;
278 buffer->height = updatedGeometry.height;
279 buffer->format = updatedGeometry.format;
280 private_handle_t *hnd = (private_handle_t*)(buffer->handle);
281 if (hnd) {
282 hnd->width = updatedGeometry.width;
283 hnd->height = updatedGeometry.height;
284 hnd->format = updatedGeometry.format;
285 } else {
286 ALOGE("%s: hnd is NULL", __FUNCTION__);
287 return -EINVAL;
288 }
289
290 return 0;
291}
292
293/* Update the S3D format of this buffer.
294*
295* @param: buffer whosei S3D format needs to be updated.
296* @param: Updated buffer S3D format
297*/
298int updateBufferS3DFormat(sp<GraphicBuffer> buffer, const int s3dFormat)
299{
300 if (buffer == 0) {
301 ALOGE("%s: graphic buffer is NULL", __FUNCTION__);
302 return -EINVAL;
303 }
304
305 buffer->format |= s3dFormat;
306 return 0;
307}
308/*
309 * Updates the flags for the layer
310 *
311 * @param: Attribute
312 * @param: Identifies if the attribute was enabled or disabled.
313 *
314 * @return: -EINVAL if the attribute is invalid
315 */
316int updateLayerQcomFlags(eLayerAttrib attribute, bool enable, int& currentFlags)
317{
318 int ret = 0;
319 switch (attribute) {
320 case LAYER_UPDATE_STATUS: {
321 if (enable)
322 currentFlags |= LAYER_UPDATING;
323 else
324 currentFlags &= ~LAYER_UPDATING;
325 } break;
326 case LAYER_ASYNCHRONOUS_STATUS: {
327 if (enable)
328 currentFlags |= LAYER_ASYNCHRONOUS;
329 else
330 currentFlags &= ~LAYER_ASYNCHRONOUS;
331 } break;
332 default: ALOGE("%s: invalid attribute(0x%x)", __FUNCTION__, attribute);
333 break;
334 }
335 return ret;
336}
337
338/*
339 * Gets the per frame HWC flags for this layer.
340 *
341 * @param: current hwcl flags
342 * @param: current layerFlags
343 *
344 * @return: the per frame flags.
345 */
346int getPerFrameFlags(int hwclFlags, int layerFlags) {
347 int flags = hwclFlags;
348 if (layerFlags & LAYER_UPDATING)
349 flags &= ~HWC_LAYER_NOT_UPDATING;
350 else
351 flags |= HWC_LAYER_NOT_UPDATING;
352
353 if (layerFlags & LAYER_ASYNCHRONOUS)
354 flags |= HWC_LAYER_ASYNCHRONOUS;
355 else
356 flags &= ~HWC_LAYER_ASYNCHRONOUS;
357
358 return flags;
359}
360
361
362/*
363 * Checks if FB is updated by this composition type
364 *
365 * @param: composition type
366 * @return: true if FB is updated, false if not
367 */
368
369bool isUpdatingFB(HWCCompositionType compositionType)
370{
371 switch(compositionType)
372 {
373 case HWC_USE_COPYBIT:
374 return true;
375 default:
376 ALOGE("%s: invalid composition type(%d)", __FUNCTION__, compositionType);
377 return false;
378 };
379}
380
381/*
382 * Get the current composition Type
383 *
384 * @return the compositon Type
385 */
386int getCompositionType() {
387 char property[PROPERTY_VALUE_MAX];
388 int compositionType = 0;
389 if (property_get("debug.sf.hw", property, NULL) > 0) {
390 if(atoi(property) == 0) {
391 compositionType = COMPOSITION_TYPE_CPU;
392 } else { //debug.sf.hw = 1
393 property_get("debug.composition.type", property, NULL);
394 if (property == NULL) {
395 compositionType = COMPOSITION_TYPE_GPU;
396 } else if ((strncmp(property, "mdp", 3)) == 0) {
397 compositionType = COMPOSITION_TYPE_MDP;
398 } else if ((strncmp(property, "c2d", 3)) == 0) {
399 compositionType = COMPOSITION_TYPE_C2D;
400 } else if ((strncmp(property, "dyn", 3)) == 0) {
401 compositionType = COMPOSITION_TYPE_DYN;
402 } else {
403 compositionType = COMPOSITION_TYPE_GPU;
404 }
405 }
406 } else { //debug.sf.hw is not set. Use cpu composition
407 compositionType = COMPOSITION_TYPE_CPU;
408 }
409 return compositionType;
410}
411
412/*
413 * Clear Region implementation for C2D/MDP versions.
414 *
415 * @param: region to be cleared
416 * @param: EGL Display
417 * @param: EGL Surface
418 *
419 * @return 0 on success
420 */
421int qcomuiClearRegion(Region region, EGLDisplay dpy, EGLSurface sur)
422{
423#if 0 /* FIXME DIE */
424 int ret = 0;
425
426 if (-1 == sCompositionType) {
427 sCompositionType = getCompositionType();
428 }
429
430 if ((COMPOSITION_TYPE_MDP != sCompositionType) &&
431 (COMPOSITION_TYPE_C2D != sCompositionType) &&
432 (COMPOSITION_TYPE_CPU != sCompositionType)) {
433 // For non CPU/C2D/MDP composition, return an error, so that SF can use
434 // the GPU to draw the wormhole.
435 return -1;
436 }
437
438 android_native_buffer_t *renderBuffer = (android_native_buffer_t *)
439 eglGetRenderBufferANDROID(dpy, sur);
440 if (!renderBuffer) {
441 ALOGE("%s: eglGetRenderBufferANDROID returned NULL buffer",
442 __FUNCTION__);
443 return -1;
444 }
445 private_handle_t *fbHandle = (private_handle_t *)renderBuffer->handle;
446 if(!fbHandle) {
447 ALOGE("%s: Framebuffer handle is NULL", __FUNCTION__);
448 return -1;
449 }
450
451 int bytesPerPixel = 4;
452 if (HAL_PIXEL_FORMAT_RGB_565 == fbHandle->format) {
453 bytesPerPixel = 2;
454 }
455
456 Region::const_iterator it = region.begin();
457 Region::const_iterator const end = region.end();
458 const int32_t stride = renderBuffer->stride*bytesPerPixel;
459 while (it != end) {
460 const Rect& r = *it++;
461 uint8_t* dst = (uint8_t*) fbHandle->base +
462 (r.left + r.top*renderBuffer->stride)*bytesPerPixel;
463 int w = r.width()*bytesPerPixel;
464 int h = r.height();
465 do {
466 if(4 == bytesPerPixel)
467 android_memset32((uint32_t*)dst, 0, w);
468 else
469 android_memset16((uint16_t*)dst, 0, w);
470 dst += stride;
471 } while(--h);
472 }
473#endif
474 return 0;
475}
476
477/*
478 * Handles the externalDisplay event
479 * HDMI has highest priority compared to WifiDisplay
480 * Based on the current and the new display event, decides the
481 * external display to be enabled
482 *
483 * @param: newEvent - new external event
484 * @param: currEvent - currently enabled external event
485 * @return: external display to be enabled
486 *
487 */
488external_display handleEventHDMI(external_display newState, external_display
489 currState)
490{
491 external_display retState = currState;
492 switch(newState) {
493 case EXT_DISPLAY_HDMI:
494 retState = EXT_DISPLAY_HDMI;
495 break;
496 case EXT_DISPLAY_WIFI:
497 if(currState != EXT_DISPLAY_HDMI) {
498 retState = EXT_DISPLAY_WIFI;
499 }
500 break;
501 case EXT_DISPLAY_OFF:
502 retState = EXT_DISPLAY_OFF;
503 break;
504 default:
505 ALOGE("handleEventHDMI: unknown Event");
506 break;
507 }
508 return retState;
509}
510
511// Using global variables for layer dumping since "property_set("debug.sf.dump",
512// property)" does not work.
513int sfdump_countlimit_raw = 0;
514int sfdump_counter_raw = 1;
515char sfdump_propstr_persist_raw[PROPERTY_VALUE_MAX] = "";
516char sfdumpdir_raw[256] = "";
517int sfdump_countlimit_png = 0;
518int sfdump_counter_png = 1;
519char sfdump_propstr_persist_png[PROPERTY_VALUE_MAX] = "";
520char sfdumpdir_png[256] = "";
521
522bool needToDumpLayers()
523{
524 bool bDumpLayer = false;
525 char sfdump_propstr[PROPERTY_VALUE_MAX];
526 time_t timenow;
527 tm sfdump_time;
528
529 time(&timenow);
530 localtime_r(&timenow, &sfdump_time);
531
532 if ((property_get("debug.sf.dump.png", sfdump_propstr, NULL) > 0) &&
533 (strncmp(sfdump_propstr, sfdump_propstr_persist_png,
534 PROPERTY_VALUE_MAX - 1))) {
535 // Strings exist & not equal implies it has changed, so trigger a dump
536 strncpy(sfdump_propstr_persist_png, sfdump_propstr,
537 PROPERTY_VALUE_MAX - 1);
538 sfdump_countlimit_png = atoi(sfdump_propstr);
539 sfdump_countlimit_png = (sfdump_countlimit_png < 0) ? 0:
540 (sfdump_countlimit_png >= LONG_MAX) ? (LONG_MAX - 1):
541 sfdump_countlimit_png;
542 if (sfdump_countlimit_png) {
543 sprintf(sfdumpdir_png,"/data/sfdump.png%04d%02d%02d.%02d%02d%02d",
544 sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1,
545 sfdump_time.tm_mday, sfdump_time.tm_hour,
546 sfdump_time.tm_min, sfdump_time.tm_sec);
547 if (0 == mkdir(sfdumpdir_png, 0777))
548 sfdump_counter_png = 0;
549 else
550 ALOGE("sfdump: Error: %s. Failed to create sfdump directory"
551 ": %s", strerror(errno), sfdumpdir_png);
552 }
553 }
554
555 if (sfdump_counter_png <= sfdump_countlimit_png)
556 sfdump_counter_png++;
557
558 if ((property_get("debug.sf.dump", sfdump_propstr, NULL) > 0) &&
559 (strncmp(sfdump_propstr, sfdump_propstr_persist_raw,
560 PROPERTY_VALUE_MAX - 1))) {
561 // Strings exist & not equal implies it has changed, so trigger a dump
562 strncpy(sfdump_propstr_persist_raw, sfdump_propstr,
563 PROPERTY_VALUE_MAX - 1);
564 sfdump_countlimit_raw = atoi(sfdump_propstr);
565 sfdump_countlimit_raw = (sfdump_countlimit_raw < 0) ? 0:
566 (sfdump_countlimit_raw >= LONG_MAX) ? (LONG_MAX - 1):
567 sfdump_countlimit_raw;
568 if (sfdump_countlimit_raw) {
569 sprintf(sfdumpdir_raw,"/data/sfdump.raw%04d%02d%02d.%02d%02d%02d",
570 sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1,
571 sfdump_time.tm_mday, sfdump_time.tm_hour,
572 sfdump_time.tm_min, sfdump_time.tm_sec);
573 if (0 == mkdir(sfdumpdir_raw, 0777))
574 sfdump_counter_raw = 0;
575 else
576 ALOGE("sfdump: Error: %s. Failed to create sfdump directory"
577 ": %s", strerror(errno), sfdumpdir_raw);
578 }
579 }
580
581 if (sfdump_counter_raw <= sfdump_countlimit_raw)
582 sfdump_counter_raw++;
583
584 bDumpLayer = (sfdump_countlimit_png || sfdump_countlimit_raw)? true : false;
585 return bDumpLayer;
586}
587
588inline void getHalPixelFormatStr(int format, char pixelformatstr[])
589{
590 if (!pixelformatstr)
591 return;
592
593 switch(format) {
594 case HAL_PIXEL_FORMAT_RGBA_8888:
595 strcpy(pixelformatstr, "RGBA_8888");
596 break;
597 case HAL_PIXEL_FORMAT_RGBX_8888:
598 strcpy(pixelformatstr, "RGBX_8888");
599 break;
600 case HAL_PIXEL_FORMAT_RGB_888:
601 strcpy(pixelformatstr, "RGB_888");
602 break;
603 case HAL_PIXEL_FORMAT_RGB_565:
604 strcpy(pixelformatstr, "RGB_565");
605 break;
606 case HAL_PIXEL_FORMAT_BGRA_8888:
607 strcpy(pixelformatstr, "BGRA_8888");
608 break;
609 case HAL_PIXEL_FORMAT_RGBA_5551:
610 strcpy(pixelformatstr, "RGBA_5551");
611 break;
612 case HAL_PIXEL_FORMAT_RGBA_4444:
613 strcpy(pixelformatstr, "RGBA_4444");
614 break;
615 case HAL_PIXEL_FORMAT_YV12:
616 strcpy(pixelformatstr, "YV12");
617 break;
618 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
619 strcpy(pixelformatstr, "YCbCr_422_SP_NV16");
620 break;
621 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
622 strcpy(pixelformatstr, "YCrCb_420_SP_NV21");
623 break;
624 case HAL_PIXEL_FORMAT_YCbCr_422_I:
625 strcpy(pixelformatstr, "YCbCr_422_I_YUY2");
626 break;
627 case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
628 strcpy(pixelformatstr, "NV12_ENCODEABLE");
629 break;
630 case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
631 strcpy(pixelformatstr, "YCbCr_420_SP_TILED_TILE_4x2");
632 break;
633 case HAL_PIXEL_FORMAT_YCbCr_420_SP:
634 strcpy(pixelformatstr, "YCbCr_420_SP");
635 break;
636 case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
637 strcpy(pixelformatstr, "YCrCb_420_SP_ADRENO");
638 break;
639 case HAL_PIXEL_FORMAT_YCrCb_422_SP:
640 strcpy(pixelformatstr, "YCrCb_422_SP");
641 break;
642 case HAL_PIXEL_FORMAT_R_8:
643 strcpy(pixelformatstr, "R_8");
644 break;
645 case HAL_PIXEL_FORMAT_RG_88:
646 strcpy(pixelformatstr, "RG_88");
647 break;
648 case HAL_PIXEL_FORMAT_INTERLACE:
649 strcpy(pixelformatstr, "INTERLACE");
650 break;
651 default:
652 sprintf(pixelformatstr, "Unknown0x%X", format);
653 break;
654 }
655}
656
657void dumpLayer(int moduleCompositionType, int listFlags, size_t layerIndex,
658 hwc_layer_t hwLayers[])
659{
660 char dumplogstr_png[128] = "";
661 char dumplogstr_raw[128] = "";
662 if (sfdump_counter_png <= sfdump_countlimit_png) {
663 sprintf(dumplogstr_png, "[png-dump-frame: %03d of %03d] ",
664 sfdump_counter_png, sfdump_countlimit_png);
665 }
666 if (sfdump_counter_raw <= sfdump_countlimit_raw) {
667 sprintf(dumplogstr_raw, "[raw-dump-frame: %03d of %03d]",
668 sfdump_counter_raw, sfdump_countlimit_raw);
669 }
670 if (NULL == hwLayers) {
671 ALOGE("sfdump: Error.%s%sLayer[%d] No hwLayers to dump.",
672 dumplogstr_raw, dumplogstr_png, layerIndex);
673 return;
674 }
675 hwc_layer *layer = &hwLayers[layerIndex];
676 hwc_rect_t sourceCrop = layer->sourceCrop;
677 hwc_rect_t displayFrame = layer->displayFrame;
678 private_handle_t *hnd = (private_handle_t *)layer->handle;
679 char pixelformatstr[32] = "None";
680
681 if (hnd)
682 getHalPixelFormatStr(hnd->format, pixelformatstr);
683#if 0
684 ALOGE("sfdump: %s%s[%s]-Composition, Layer[%d] SrcBuff[%dx%d] "
685 "SrcCrop[%dl, %dt, %dr, %db] "
686 "DispFrame[%dl, %dt, %dr, %db] Composition-type = %s, Format = %s, "
687 "Orientation = %s, Flags = %s%s%s%s%s%s%s%s%s%s",
688 dumplogstr_raw, dumplogstr_png,
689 (moduleCompositionType == COMPOSITION_TYPE_GPU)? "GPU":
690 (moduleCompositionType == COMPOSITION_TYPE_MDP)? "MDP":
691 (moduleCompositionType == COMPOSITION_TYPE_C2D)? "C2D":
692 (moduleCompositionType == COMPOSITION_TYPE_CPU)? "CPU":
693 (moduleCompositionType == COMPOSITION_TYPE_DYN)? "DYN": "???",
694 layerIndex,
695 (hnd)? hnd->width : -1, (hnd)? hnd->height : -1,
696 sourceCrop.left, sourceCrop.top,
697 sourceCrop.right, sourceCrop.bottom,
698 displayFrame.left, displayFrame.top,
699 displayFrame.right, displayFrame.bottom,
700 (layer->compositionType == HWC_FRAMEBUFFER)? "Framebuffer (OpenGL ES)":
701 (layer->compositionType == HWC_OVERLAY)? "Overlay":
702 (layer->compositionType == HWC_USE_COPYBIT)? "Copybit": "???",
703 pixelformatstr,
704 (layer->transform == Transform::ROT_0)? "ROT_0":
705 (layer->transform == Transform::FLIP_H)? "FLIP_H":
706 (layer->transform == Transform::FLIP_V)? "FLIP_V":
707 (layer->transform == Transform::ROT_90)? "ROT_90":
708 (layer->transform == Transform::ROT_180)? "ROT_180":
709 (layer->transform == Transform::ROT_270)? "ROT_270":
710 (layer->transform == Transform::ROT_INVALID)? "ROT_INVALID":"???",
711 (layer->flags == 0)? "[None]":"",
712 (layer->flags & HWC_SKIP_LAYER)? "[Skip layer]":"",
713 (layer->flags & HWC_LAYER_NOT_UPDATING)? "[Layer not updating]":"",
714 (layer->flags & HWC_USE_ORIGINAL_RESOLUTION)? "[Original Resolution]":"",
715 (layer->flags & HWC_DO_NOT_USE_OVERLAY)? "[Do not use Overlay]":"",
716 (layer->flags & HWC_COMP_BYPASS)? "[Bypass]":"",
717 (layer->flags & HWC_BYPASS_RESERVE_0)? "[Bypass Reserve 0]":"",
718 (layer->flags & HWC_BYPASS_RESERVE_1)? "[Bypass Reserve 1]":"",
719 (listFlags & HWC_GEOMETRY_CHANGED)? "[List: Geometry Changed]":"",
720 (listFlags & HWC_SKIP_COMPOSITION)? "[List: Skip Composition]":"");
721#endif
722 if (NULL == hnd) {
723 ALOGE("sfdump: %s%sLayer[%d] private-handle is invalid.",
724 dumplogstr_raw, dumplogstr_png, layerIndex);
725 return;
726 }
727
728 if ((sfdump_counter_png <= sfdump_countlimit_png) && hnd->base) {
729 bool bResult = false;
730 char sfdumpfile_name[256];
731 SkBitmap *tempSkBmp = new SkBitmap();
732 SkBitmap::Config tempSkBmpConfig = SkBitmap::kNo_Config;
733 sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d.png", sfdumpdir_png,
734 sfdump_counter_png, layerIndex);
735
736 switch (hnd->format) {
737 case HAL_PIXEL_FORMAT_RGBA_8888:
738 case HAL_PIXEL_FORMAT_RGBX_8888:
739 case HAL_PIXEL_FORMAT_BGRA_8888:
740 tempSkBmpConfig = SkBitmap::kARGB_8888_Config;
741 break;
742 case HAL_PIXEL_FORMAT_RGB_565:
743 case HAL_PIXEL_FORMAT_RGBA_5551:
744 case HAL_PIXEL_FORMAT_RGBA_4444:
745 tempSkBmpConfig = SkBitmap::kRGB_565_Config;
746 break;
747 case HAL_PIXEL_FORMAT_RGB_888:
748 default:
749 tempSkBmpConfig = SkBitmap::kNo_Config;
750 break;
751 }
752 if (SkBitmap::kNo_Config != tempSkBmpConfig) {
753 tempSkBmp->setConfig(tempSkBmpConfig, hnd->width, hnd->height);
754 tempSkBmp->setPixels((void*)hnd->base);
755 bResult = SkImageEncoder::EncodeFile(sfdumpfile_name,
756 *tempSkBmp, SkImageEncoder::kPNG_Type, 100);
757 ALOGE("sfdump: %sDumped Layer[%d] to %s: %s", dumplogstr_png,
758 layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail");
759 }
760 else {
761 ALOGE("sfdump: %sSkipping Layer[%d] dump: Unsupported layer "
762 "format %s for png encoder.", dumplogstr_png, layerIndex,
763 pixelformatstr);
764 }
765 delete tempSkBmp; // Calls SkBitmap::freePixels() internally.
766 }
767
768 if ((sfdump_counter_raw <= sfdump_countlimit_raw) && hnd->base) {
769 char sfdumpfile_name[256];
770 bool bResult = false;
771 sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d_%dx%d_%s.raw",
772 sfdumpdir_raw,
773 sfdump_counter_raw, layerIndex, hnd->width, hnd->height,
774 pixelformatstr);
775 FILE* fp = fopen(sfdumpfile_name, "w+");
776 if (fp != NULL) {
777 bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp);
778 fclose(fp);
779 }
780 ALOGE("sfdump: %s Dumped Layer[%d] to %s: %s", dumplogstr_raw,
781 layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail");
782 }
783}
784
785#ifdef DEBUG_CALC_FPS
786ANDROID_SINGLETON_STATIC_INSTANCE(CalcFps) ;
787
788CalcFps::CalcFps() {
789 debug_fps_level = 0;
790 Init();
791}
792
793CalcFps::~CalcFps() {
794}
795
796void CalcFps::Init() {
797 char prop[PROPERTY_VALUE_MAX];
798 property_get("debug.gr.calcfps", prop, "0");
799 debug_fps_level = atoi(prop);
800 if (debug_fps_level > MAX_DEBUG_FPS_LEVEL) {
801 ALOGW("out of range value for debug.gr.calcfps, using 0");
802 debug_fps_level = 0;
803 }
804
805 ALOGE("DEBUG_CALC_FPS: %d", debug_fps_level);
806 populate_debug_fps_metadata();
807}
808
809void CalcFps::Fps() {
810 if (debug_fps_level > 0)
811 calc_fps(ns2us(systemTime()));
812}
813
814void CalcFps::populate_debug_fps_metadata(void)
815{
816 char prop[PROPERTY_VALUE_MAX];
817
818 /*defaults calculation of fps to based on number of frames*/
819 property_get("debug.gr.calcfps.type", prop, "0");
820 debug_fps_metadata.type = (debug_fps_metadata_t::DfmType) atoi(prop);
821
822 /*defaults to 1000ms*/
823 property_get("debug.gr.calcfps.timeperiod", prop, "1000");
824 debug_fps_metadata.time_period = atoi(prop);
825
826 property_get("debug.gr.calcfps.period", prop, "10");
827 debug_fps_metadata.period = atoi(prop);
828
829 if (debug_fps_metadata.period > MAX_FPS_CALC_PERIOD_IN_FRAMES) {
830 debug_fps_metadata.period = MAX_FPS_CALC_PERIOD_IN_FRAMES;
831 }
832
833 /* default ignorethresh_us: 500 milli seconds */
834 property_get("debug.gr.calcfps.ignorethresh_us", prop, "500000");
835 debug_fps_metadata.ignorethresh_us = atoi(prop);
836
837 debug_fps_metadata.framearrival_steps =
838 (debug_fps_metadata.ignorethresh_us / 16666);
839
840 if (debug_fps_metadata.framearrival_steps > MAX_FRAMEARRIVAL_STEPS) {
841 debug_fps_metadata.framearrival_steps = MAX_FRAMEARRIVAL_STEPS;
842 debug_fps_metadata.ignorethresh_us =
843 debug_fps_metadata.framearrival_steps * 16666;
844 }
845
846 /* 2ms margin of error for the gettimeofday */
847 debug_fps_metadata.margin_us = 2000;
848
849 for (unsigned int i = 0; i < MAX_FRAMEARRIVAL_STEPS; i++)
850 debug_fps_metadata.accum_framearrivals[i] = 0;
851
852 ALOGE("period: %d", debug_fps_metadata.period);
853 ALOGE("ignorethresh_us: %lld", debug_fps_metadata.ignorethresh_us);
854}
855
856void CalcFps::print_fps(float fps)
857{
858 if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type)
859 ALOGE("FPS for last %d frames: %3.2f", debug_fps_metadata.period, fps);
860 else
861 ALOGE("FPS for last (%f ms, %d frames): %3.2f",
862 debug_fps_metadata.time_elapsed,
863 debug_fps_metadata.curr_frame, fps);
864
865 debug_fps_metadata.curr_frame = 0;
866 debug_fps_metadata.time_elapsed = 0.0;
867
868 if (debug_fps_level > 1) {
869 ALOGE("Frame Arrival Distribution:");
870 for (unsigned int i = 0;
871 i < ((debug_fps_metadata.framearrival_steps / 6) + 1);
872 i++) {
873 ALOGE("%lld %lld %lld %lld %lld %lld",
874 debug_fps_metadata.accum_framearrivals[i*6],
875 debug_fps_metadata.accum_framearrivals[i*6+1],
876 debug_fps_metadata.accum_framearrivals[i*6+2],
877 debug_fps_metadata.accum_framearrivals[i*6+3],
878 debug_fps_metadata.accum_framearrivals[i*6+4],
879 debug_fps_metadata.accum_framearrivals[i*6+5]);
880 }
881
882 /* We are done with displaying, now clear the stats */
883 for (unsigned int i = 0;
884 i < debug_fps_metadata.framearrival_steps;
885 i++)
886 debug_fps_metadata.accum_framearrivals[i] = 0;
887 }
888 return;
889}
890
891void CalcFps::calc_fps(nsecs_t currtime_us)
892{
893 static nsecs_t oldtime_us = 0;
894
895 nsecs_t diff = currtime_us - oldtime_us;
896
897 oldtime_us = currtime_us;
898
899 if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type &&
900 diff > debug_fps_metadata.ignorethresh_us) {
901 return;
902 }
903
904 if (debug_fps_metadata.curr_frame < MAX_FPS_CALC_PERIOD_IN_FRAMES) {
905 debug_fps_metadata.framearrivals[debug_fps_metadata.curr_frame] = diff;
906 }
907
908 debug_fps_metadata.curr_frame++;
909
910 if (debug_fps_level > 1) {
911 unsigned int currstep = (diff + debug_fps_metadata.margin_us) / 16666;
912
913 if (currstep < debug_fps_metadata.framearrival_steps) {
914 debug_fps_metadata.accum_framearrivals[currstep-1]++;
915 }
916 }
917
918 if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type) {
919 if (debug_fps_metadata.curr_frame == debug_fps_metadata.period) {
920 /* time to calculate and display FPS */
921 nsecs_t sum = 0;
922 for (unsigned int i = 0; i < debug_fps_metadata.period; i++)
923 sum += debug_fps_metadata.framearrivals[i];
924 print_fps((debug_fps_metadata.period * float(1000000))/float(sum));
925 }
926 }
927 else if (debug_fps_metadata_t::DFM_TIME == debug_fps_metadata.type) {
928 debug_fps_metadata.time_elapsed += ((float)diff/1000.0);
929 if (debug_fps_metadata.time_elapsed >= debug_fps_metadata.time_period) {
930 float fps = (1000.0 * debug_fps_metadata.curr_frame)/
931 (float)debug_fps_metadata.time_elapsed;
932 print_fps(fps);
933 }
934 }
935 return;
936}
937#endif