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