| /* |
| * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. |
| |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of Code Aurora Forum, Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <cutils/log.h> |
| #include <cutils/memory.h> |
| #include <qcom_ui.h> |
| #include <utils/comptype.h> |
| #include <gralloc_priv.h> |
| #include <alloc_controller.h> |
| #include <memalloc.h> |
| #include <errno.h> |
| #include <EGL/eglext.h> |
| #include <sys/stat.h> |
| #include <SkBitmap.h> |
| #include <SkImageEncoder.h> |
| #include <Transform.h> |
| |
| using gralloc::IMemAlloc; |
| using gralloc::IonController; |
| using gralloc::alloc_data; |
| using android::sp; |
| namespace { |
| |
| static android::sp<gralloc::IAllocController> sAlloc = 0; |
| |
| int reallocate_memory(native_handle_t *buffer_handle, int mReqSize, int usage) |
| { |
| int ret = 0; |
| |
| #ifndef NON_QCOM_TARGET |
| if (sAlloc == 0) { |
| sAlloc = gralloc::IAllocController::getInstance(true); |
| } |
| if (sAlloc == 0) { |
| LOGE("sAlloc is still NULL"); |
| return -EINVAL; |
| } |
| |
| // Dealloc the old memory |
| private_handle_t *hnd = (private_handle_t *)buffer_handle; |
| sp<IMemAlloc> memalloc = sAlloc->getAllocator(hnd->flags); |
| ret = memalloc->free_buffer((void*)hnd->base, hnd->size, hnd->offset, hnd->fd); |
| |
| if (ret) { |
| LOGE("%s: free_buffer failed", __FUNCTION__); |
| return -1; |
| } |
| |
| // Realloc new memory |
| alloc_data data; |
| data.base = 0; |
| data.fd = -1; |
| data.offset = 0; |
| data.size = mReqSize; |
| data.align = getpagesize(); |
| data.uncached = true; |
| int allocFlags = usage; |
| |
| switch (hnd->format) { |
| case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: |
| case (HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED^HAL_PIXEL_FORMAT_INTERLACE): { |
| data.align = 8192; |
| } break; |
| default: break; |
| } |
| ret = sAlloc->allocate(data, allocFlags, 0); |
| if (ret == 0) { |
| hnd->fd = data.fd; |
| hnd->base = (int)data.base; |
| hnd->offset = data.offset; |
| hnd->size = data.size; |
| } else { |
| LOGE("%s: allocate failed", __FUNCTION__); |
| return -EINVAL; |
| } |
| #endif |
| return ret; |
| } |
| }; // ANONYNMOUS NAMESPACE |
| |
| /* |
| * Gets the number of arguments required for this operation. |
| * |
| * @param: operation whose argument count is required. |
| * |
| * @return -EINVAL if the operation is invalid. |
| */ |
| int getNumberOfArgsForOperation(int operation) { |
| int num_args = -EINVAL; |
| switch(operation) { |
| case NATIVE_WINDOW_SET_BUFFERS_SIZE: |
| num_args = 1; |
| break; |
| case NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY: |
| num_args = 3; |
| break; |
| case NATIVE_WINDOW_SET_PIXEL_ASPECT_RATIO: |
| num_args = 2; |
| break; |
| default: LOGE("%s: invalid operation(0x%x)", __FUNCTION__, operation); |
| break; |
| }; |
| return num_args; |
| } |
| |
| /* |
| * Checks if the format is supported by the GPU. |
| * |
| * @param: format to check |
| * |
| * @return true if the format is supported by the GPU. |
| */ |
| bool isGPUSupportedFormat(int format) { |
| if (format == HAL_PIXEL_FORMAT_YV12) { |
| // We check the YV12 formats, since some Qcom specific formats |
| // could have the bits set. |
| return true; |
| } else if ((format == HAL_PIXEL_FORMAT_RGB_888) || |
| (format == HAL_PIXEL_FORMAT_YCrCb_422_SP) || |
| (format == HAL_PIXEL_FORMAT_YCbCr_422_SP)){ |
| return false; |
| } else if (format & INTERLACE_MASK) { |
| // Interlaced content |
| return false; |
| } else if (format & S3D_FORMAT_MASK) { |
| // S3D Formats are not supported by the GPU |
| return false; |
| } |
| return true; |
| } |
| |
| /* |
| * Function to check if the allocated buffer is of the correct size. |
| * Reallocate the buffer with the correct size, if the size doesn't |
| * match |
| * |
| * @param: handle of the allocated buffer |
| * @param: requested size for the buffer |
| * @param: usage flags |
| * |
| * return 0 on success |
| */ |
| int checkBuffer(native_handle_t *buffer_handle, int size, int usage) |
| { |
| // If the client hasn't set a size, return |
| if (0 >= size) { |
| return 0; |
| } |
| |
| // Validate the handle |
| if (private_handle_t::validate(buffer_handle)) { |
| LOGE("%s: handle is invalid", __FUNCTION__); |
| return -EINVAL; |
| } |
| |
| // Obtain the private_handle from the native handle |
| private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle); |
| if (hnd->size != size) { |
| return reallocate_memory(hnd, size, usage); |
| } |
| return 0; |
| } |
| |
| /* |
| * Checks if memory needs to be reallocated for this buffer. |
| * |
| * @param: Geometry of the current buffer. |
| * @param: Required Geometry. |
| * @param: Geometry of the updated buffer. |
| * |
| * @return True if a memory reallocation is required. |
| */ |
| bool needNewBuffer(const qBufGeometry currentGeometry, |
| const qBufGeometry requiredGeometry, |
| const qBufGeometry updatedGeometry) |
| { |
| // If the current buffer info matches the updated info, |
| // we do not require any memory allocation. |
| if (updatedGeometry.width && updatedGeometry.height && |
| updatedGeometry.format) { |
| return false; |
| } |
| if (currentGeometry.width != requiredGeometry.width || |
| currentGeometry.height != requiredGeometry.height || |
| currentGeometry.format != requiredGeometry.format) { |
| // Current and required geometry do not match. Allocation |
| // required. |
| return true; |
| } |
| return false; |
| } |
| |
| /* |
| * Update the geometry of this buffer without reallocation. |
| * |
| * @param: buffer whose geometry needs to be updated. |
| * @param: Updated width |
| * @param: Updated height |
| * @param: Updated format |
| */ |
| int updateBufferGeometry(sp<GraphicBuffer> buffer, const qBufGeometry updatedGeometry) |
| { |
| if (buffer == 0) { |
| LOGE("%s: graphic buffer is NULL", __FUNCTION__); |
| return -EINVAL; |
| } |
| |
| if (!updatedGeometry.width || !updatedGeometry.height || |
| !updatedGeometry.format) { |
| // No update required. Return. |
| return 0; |
| } |
| if (buffer->width == updatedGeometry.width && |
| buffer->height == updatedGeometry.height && |
| buffer->format == updatedGeometry.format) { |
| // The buffer has already been updated. Return. |
| return 0; |
| } |
| |
| // Validate the handle |
| if (private_handle_t::validate(buffer->handle)) { |
| LOGE("%s: handle is invalid", __FUNCTION__); |
| return -EINVAL; |
| } |
| buffer->width = updatedGeometry.width; |
| buffer->height = updatedGeometry.height; |
| buffer->format = updatedGeometry.format; |
| private_handle_t *hnd = (private_handle_t*)(buffer->handle); |
| if (hnd) { |
| hnd->width = updatedGeometry.width; |
| hnd->height = updatedGeometry.height; |
| hnd->format = updatedGeometry.format; |
| } else { |
| LOGE("%s: hnd is NULL", __FUNCTION__); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| /* Update the S3D format of this buffer. |
| * |
| * @param: buffer whosei S3D format needs to be updated. |
| * @param: Updated buffer S3D format |
| */ |
| int updateBufferS3DFormat(sp<GraphicBuffer> buffer, const int s3dFormat) |
| { |
| if (buffer == 0) { |
| LOGE("%s: graphic buffer is NULL", __FUNCTION__); |
| return -EINVAL; |
| } |
| |
| buffer->format |= s3dFormat; |
| return 0; |
| } |
| /* |
| * Updates the flags for the layer |
| * |
| * @param: Attribute |
| * @param: Identifies if the attribute was enabled or disabled. |
| * |
| * @return: -EINVAL if the attribute is invalid |
| */ |
| int updateLayerQcomFlags(eLayerAttrib attribute, bool enable, int& currentFlags) |
| { |
| int ret = 0; |
| switch (attribute) { |
| case LAYER_UPDATE_STATUS: { |
| if (enable) |
| currentFlags |= LAYER_UPDATING; |
| else |
| currentFlags &= ~LAYER_UPDATING; |
| } break; |
| case LAYER_ASYNCHRONOUS_STATUS: { |
| if (enable) |
| currentFlags |= LAYER_ASYNCHRONOUS; |
| else |
| currentFlags &= ~LAYER_ASYNCHRONOUS; |
| } break; |
| default: LOGE("%s: invalid attribute(0x%x)", __FUNCTION__, attribute); |
| break; |
| } |
| return ret; |
| } |
| |
| /* |
| * Gets the per frame HWC flags for this layer. |
| * |
| * @param: current hwcl flags |
| * @param: current layerFlags |
| * |
| * @return: the per frame flags. |
| */ |
| int getPerFrameFlags(int hwclFlags, int layerFlags) { |
| int flags = hwclFlags; |
| if (layerFlags & LAYER_UPDATING) |
| flags &= ~HWC_LAYER_NOT_UPDATING; |
| else |
| flags |= HWC_LAYER_NOT_UPDATING; |
| |
| if (layerFlags & LAYER_ASYNCHRONOUS) |
| flags |= HWC_LAYER_ASYNCHRONOUS; |
| else |
| flags &= ~HWC_LAYER_ASYNCHRONOUS; |
| |
| return flags; |
| } |
| |
| |
| /* |
| * Checks if FB is updated by this composition type |
| * |
| * @param: composition type |
| * @return: true if FB is updated, false if not |
| */ |
| |
| bool isUpdatingFB(HWCCompositionType compositionType) |
| { |
| switch(compositionType) |
| { |
| case HWC_USE_COPYBIT: |
| return true; |
| default: |
| LOGE("%s: invalid composition type(%d)", __FUNCTION__, compositionType); |
| return false; |
| }; |
| } |
| |
| /* |
| * Clear Region implementation for C2D/MDP versions. |
| * |
| * @param: region to be cleared |
| * @param: EGL Display |
| * @param: EGL Surface |
| * |
| * @return 0 on success |
| */ |
| int qcomuiClearRegion(Region region, EGLDisplay dpy, EGLSurface sur) |
| { |
| int ret = 0; |
| int compositionType = QCCompositionType::getInstance().getCompositionType(); |
| |
| if (compositionType & COMPOSITION_TYPE_GPU || |
| (compositionType == COMPOSITION_TYPE_DYN|COMPOSITION_TYPE_C2D)) |
| { |
| // For GPU or DYN comp. with C2D, return an error, so that SF can use |
| // the GPU to draw the wormhole. |
| return -1; |
| } |
| |
| android_native_buffer_t *renderBuffer = (android_native_buffer_t *) |
| eglGetRenderBufferANDROID(dpy, sur); |
| if (!renderBuffer) { |
| LOGE("%s: eglGetRenderBufferANDROID returned NULL buffer", |
| __FUNCTION__); |
| return -1; |
| } |
| private_handle_t *fbHandle = (private_handle_t *)renderBuffer->handle; |
| if(!fbHandle) { |
| LOGE("%s: Framebuffer handle is NULL", __FUNCTION__); |
| return -1; |
| } |
| |
| int bytesPerPixel = 4; |
| if (HAL_PIXEL_FORMAT_RGB_565 == fbHandle->format) { |
| bytesPerPixel = 2; |
| } |
| |
| Region::const_iterator it = region.begin(); |
| Region::const_iterator const end = region.end(); |
| const int32_t stride = renderBuffer->stride*bytesPerPixel; |
| while (it != end) { |
| const Rect& r = *it++; |
| uint8_t* dst = (uint8_t*) fbHandle->base + |
| (r.left + r.top*renderBuffer->stride)*bytesPerPixel; |
| int w = r.width()*bytesPerPixel; |
| int h = r.height(); |
| do { |
| if(4 == bytesPerPixel) |
| android_memset32((uint32_t*)dst, 0, w); |
| else |
| android_memset16((uint16_t*)dst, 0, w); |
| dst += stride; |
| } while(--h); |
| } |
| return 0; |
| } |
| |
| /* |
| * Handles the externalDisplay event |
| * HDMI has highest priority compared to WifiDisplay |
| * Based on the current and the new display type, decides the |
| * external display to be enabled |
| * |
| * @param: disp - external display type(wfd/hdmi) |
| * @param: value - external event(0/1) |
| * @param: currdispType - Current enabled external display Type |
| * @return: external display type to be enabled |
| * |
| */ |
| external_display_type handleEventHDMI(external_display_type disp, int value, |
| external_display_type currDispType) |
| { |
| external_display_type retDispType = currDispType; |
| switch(disp) { |
| case EXT_TYPE_HDMI: |
| if(value) |
| retDispType = EXT_TYPE_HDMI; |
| else |
| retDispType = EXT_TYPE_NONE; |
| break; |
| case EXT_TYPE_WIFI: |
| if(currDispType != EXT_TYPE_HDMI) { |
| if(value) |
| retDispType = EXT_TYPE_WIFI; |
| else |
| retDispType = EXT_TYPE_NONE; |
| } |
| break; |
| default: |
| LOGE("%s: Unknown External Display Type!!"); |
| break; |
| } |
| return retDispType; |
| } |
| |
| // Using global variables for layer dumping since "property_set("debug.sf.dump", |
| // property)" does not work. |
| int sfdump_countlimit_raw = 0; |
| int sfdump_counter_raw = 1; |
| char sfdump_propstr_persist_raw[PROPERTY_VALUE_MAX] = ""; |
| char sfdumpdir_raw[256] = ""; |
| int sfdump_countlimit_png = 0; |
| int sfdump_counter_png = 1; |
| char sfdump_propstr_persist_png[PROPERTY_VALUE_MAX] = ""; |
| char sfdumpdir_png[256] = ""; |
| |
| bool needToDumpLayers() |
| { |
| bool bDumpLayer = false; |
| char sfdump_propstr[PROPERTY_VALUE_MAX]; |
| time_t timenow; |
| tm sfdump_time; |
| |
| time(&timenow); |
| localtime_r(&timenow, &sfdump_time); |
| |
| if ((property_get("debug.sf.dump.png", sfdump_propstr, NULL) > 0) && |
| (strncmp(sfdump_propstr, sfdump_propstr_persist_png, |
| PROPERTY_VALUE_MAX - 1))) { |
| // Strings exist & not equal implies it has changed, so trigger a dump |
| strncpy(sfdump_propstr_persist_png, sfdump_propstr, |
| PROPERTY_VALUE_MAX - 1); |
| sfdump_countlimit_png = atoi(sfdump_propstr); |
| sfdump_countlimit_png = (sfdump_countlimit_png < 0) ? 0: |
| (sfdump_countlimit_png >= LONG_MAX) ? (LONG_MAX - 1): |
| sfdump_countlimit_png; |
| if (sfdump_countlimit_png) { |
| sprintf(sfdumpdir_png,"/data/sfdump.png%04d%02d%02d.%02d%02d%02d", |
| sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1, |
| sfdump_time.tm_mday, sfdump_time.tm_hour, |
| sfdump_time.tm_min, sfdump_time.tm_sec); |
| if (0 == mkdir(sfdumpdir_png, 0777)) |
| sfdump_counter_png = 0; |
| else |
| LOGE("sfdump: Error: %s. Failed to create sfdump directory" |
| ": %s", strerror(errno), sfdumpdir_png); |
| } |
| } |
| |
| if (sfdump_counter_png <= sfdump_countlimit_png) |
| sfdump_counter_png++; |
| |
| if ((property_get("debug.sf.dump", sfdump_propstr, NULL) > 0) && |
| (strncmp(sfdump_propstr, sfdump_propstr_persist_raw, |
| PROPERTY_VALUE_MAX - 1))) { |
| // Strings exist & not equal implies it has changed, so trigger a dump |
| strncpy(sfdump_propstr_persist_raw, sfdump_propstr, |
| PROPERTY_VALUE_MAX - 1); |
| sfdump_countlimit_raw = atoi(sfdump_propstr); |
| sfdump_countlimit_raw = (sfdump_countlimit_raw < 0) ? 0: |
| (sfdump_countlimit_raw >= LONG_MAX) ? (LONG_MAX - 1): |
| sfdump_countlimit_raw; |
| if (sfdump_countlimit_raw) { |
| sprintf(sfdumpdir_raw,"/data/sfdump.raw%04d%02d%02d.%02d%02d%02d", |
| sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1, |
| sfdump_time.tm_mday, sfdump_time.tm_hour, |
| sfdump_time.tm_min, sfdump_time.tm_sec); |
| if (0 == mkdir(sfdumpdir_raw, 0777)) |
| sfdump_counter_raw = 0; |
| else |
| LOGE("sfdump: Error: %s. Failed to create sfdump directory" |
| ": %s", strerror(errno), sfdumpdir_raw); |
| } |
| } |
| |
| if (sfdump_counter_raw <= sfdump_countlimit_raw) |
| sfdump_counter_raw++; |
| |
| bDumpLayer = (sfdump_countlimit_png || sfdump_countlimit_raw)? true : false; |
| return bDumpLayer; |
| } |
| |
| inline void getHalPixelFormatStr(int format, char pixelformatstr[]) |
| { |
| if (!pixelformatstr) |
| return; |
| |
| switch(format) { |
| case HAL_PIXEL_FORMAT_RGBA_8888: |
| strcpy(pixelformatstr, "RGBA_8888"); |
| break; |
| case HAL_PIXEL_FORMAT_RGBX_8888: |
| strcpy(pixelformatstr, "RGBX_8888"); |
| break; |
| case HAL_PIXEL_FORMAT_RGB_888: |
| strcpy(pixelformatstr, "RGB_888"); |
| break; |
| case HAL_PIXEL_FORMAT_RGB_565: |
| strcpy(pixelformatstr, "RGB_565"); |
| break; |
| case HAL_PIXEL_FORMAT_BGRA_8888: |
| strcpy(pixelformatstr, "BGRA_8888"); |
| break; |
| case HAL_PIXEL_FORMAT_RGBA_5551: |
| strcpy(pixelformatstr, "RGBA_5551"); |
| break; |
| case HAL_PIXEL_FORMAT_RGBA_4444: |
| strcpy(pixelformatstr, "RGBA_4444"); |
| break; |
| case HAL_PIXEL_FORMAT_YV12: |
| strcpy(pixelformatstr, "YV12"); |
| break; |
| case HAL_PIXEL_FORMAT_YCbCr_422_SP: |
| strcpy(pixelformatstr, "YCbCr_422_SP_NV16"); |
| break; |
| case HAL_PIXEL_FORMAT_YCrCb_420_SP: |
| strcpy(pixelformatstr, "YCrCb_420_SP_NV21"); |
| break; |
| case HAL_PIXEL_FORMAT_YCbCr_422_I: |
| strcpy(pixelformatstr, "YCbCr_422_I_YUY2"); |
| break; |
| case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: |
| strcpy(pixelformatstr, "NV12_ENCODEABLE"); |
| break; |
| case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: |
| strcpy(pixelformatstr, "YCbCr_420_SP_TILED_TILE_4x2"); |
| break; |
| case HAL_PIXEL_FORMAT_YCbCr_420_SP: |
| strcpy(pixelformatstr, "YCbCr_420_SP"); |
| break; |
| case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: |
| strcpy(pixelformatstr, "YCrCb_420_SP_ADRENO"); |
| break; |
| case HAL_PIXEL_FORMAT_YCrCb_422_SP: |
| strcpy(pixelformatstr, "YCrCb_422_SP"); |
| break; |
| case HAL_PIXEL_FORMAT_R_8: |
| strcpy(pixelformatstr, "R_8"); |
| break; |
| case HAL_PIXEL_FORMAT_RG_88: |
| strcpy(pixelformatstr, "RG_88"); |
| break; |
| case HAL_PIXEL_FORMAT_INTERLACE: |
| strcpy(pixelformatstr, "INTERLACE"); |
| break; |
| default: |
| sprintf(pixelformatstr, "Unknown0x%X", format); |
| break; |
| } |
| } |
| |
| void dumpLayer(int moduleCompositionType, int listFlags, size_t layerIndex, |
| hwc_layer_t hwLayers[]) |
| { |
| char dumplogstr_png[128] = ""; |
| char dumplogstr_raw[128] = ""; |
| if (sfdump_counter_png <= sfdump_countlimit_png) { |
| sprintf(dumplogstr_png, "[png-dump-frame: %03d of %03d] ", |
| sfdump_counter_png, sfdump_countlimit_png); |
| } |
| if (sfdump_counter_raw <= sfdump_countlimit_raw) { |
| sprintf(dumplogstr_raw, "[raw-dump-frame: %03d of %03d]", |
| sfdump_counter_raw, sfdump_countlimit_raw); |
| } |
| if (NULL == hwLayers) { |
| LOGE("sfdump: Error.%s%sLayer[%d] No hwLayers to dump.", |
| dumplogstr_raw, dumplogstr_png, layerIndex); |
| return; |
| } |
| hwc_layer *layer = &hwLayers[layerIndex]; |
| hwc_rect_t sourceCrop = layer->sourceCrop; |
| hwc_rect_t displayFrame = layer->displayFrame; |
| private_handle_t *hnd = (private_handle_t *)layer->handle; |
| char pixelformatstr[32] = "None"; |
| uint32_t transform = layer->transform & FINAL_TRANSFORM_MASK; |
| |
| if (hnd) |
| getHalPixelFormatStr(hnd->format, pixelformatstr); |
| |
| LOGE("sfdump: %s%s[%s]-Composition, Layer[%d] SrcBuff[%dx%d] " |
| "SrcCrop[%dl, %dt, %dr, %db] " |
| "DispFrame[%dl, %dt, %dr, %db] Composition-type = %s, Format = %s, " |
| "Orientation = %s, Flags = %s%s%s%s%s%s%s%s%s%s", |
| dumplogstr_raw, dumplogstr_png, |
| (moduleCompositionType == COMPOSITION_TYPE_GPU)? "GPU": |
| (moduleCompositionType == COMPOSITION_TYPE_MDP)? "MDP": |
| (moduleCompositionType == COMPOSITION_TYPE_C2D)? "C2D": |
| (moduleCompositionType == COMPOSITION_TYPE_CPU)? "CPU": |
| (moduleCompositionType == COMPOSITION_TYPE_DYN)? "DYN": "???", |
| layerIndex, |
| (hnd)? hnd->width : -1, (hnd)? hnd->height : -1, |
| sourceCrop.left, sourceCrop.top, |
| sourceCrop.right, sourceCrop.bottom, |
| displayFrame.left, displayFrame.top, |
| displayFrame.right, displayFrame.bottom, |
| (layer->compositionType == HWC_FRAMEBUFFER)? "Framebuffer (OpenGL ES)": |
| (layer->compositionType == HWC_OVERLAY)? "Overlay": |
| (layer->compositionType == HWC_USE_COPYBIT)? "Copybit": "???", |
| pixelformatstr, |
| (transform == Transform::ROT_0)? "ROT_0": |
| (transform == Transform::FLIP_H)? "FLIP_H": |
| (transform == Transform::FLIP_V)? "FLIP_V": |
| (transform == Transform::ROT_90)? "ROT_90": |
| (transform == Transform::ROT_180)? "ROT_180": |
| (transform == Transform::ROT_270)? "ROT_270": |
| (transform == Transform::ROT_INVALID)? "ROT_INVALID":"???", |
| (layer->flags == 0)? "[None]":"", |
| (layer->flags & HWC_SKIP_LAYER)? "[Skip layer]":"", |
| (layer->flags & HWC_LAYER_NOT_UPDATING)? "[Layer not updating]":"", |
| (layer->flags & HWC_COMP_BYPASS)? "[Bypass]":"", |
| (layer->flags & HWC_BYPASS_RESERVE_0)? "[Bypass Reserve 0]":"", |
| (layer->flags & HWC_BYPASS_RESERVE_1)? "[Bypass Reserve 1]":"", |
| (listFlags & HWC_GEOMETRY_CHANGED)? "[List: Geometry Changed]":"", |
| (listFlags & HWC_SKIP_COMPOSITION)? "[List: Skip Composition]":""); |
| |
| if (NULL == hnd) { |
| LOGE("sfdump: %s%sLayer[%d] private-handle is invalid.", |
| dumplogstr_raw, dumplogstr_png, layerIndex); |
| return; |
| } |
| |
| if ((sfdump_counter_png <= sfdump_countlimit_png) && hnd->base) { |
| bool bResult = false; |
| char sfdumpfile_name[256]; |
| SkBitmap *tempSkBmp = new SkBitmap(); |
| SkBitmap::Config tempSkBmpConfig = SkBitmap::kNo_Config; |
| sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d.png", sfdumpdir_png, |
| sfdump_counter_png, layerIndex); |
| |
| switch (hnd->format) { |
| case HAL_PIXEL_FORMAT_RGBA_8888: |
| case HAL_PIXEL_FORMAT_RGBX_8888: |
| case HAL_PIXEL_FORMAT_BGRA_8888: |
| tempSkBmpConfig = SkBitmap::kARGB_8888_Config; |
| break; |
| case HAL_PIXEL_FORMAT_RGB_565: |
| case HAL_PIXEL_FORMAT_RGBA_5551: |
| case HAL_PIXEL_FORMAT_RGBA_4444: |
| tempSkBmpConfig = SkBitmap::kRGB_565_Config; |
| break; |
| case HAL_PIXEL_FORMAT_RGB_888: |
| default: |
| tempSkBmpConfig = SkBitmap::kNo_Config; |
| break; |
| } |
| if (SkBitmap::kNo_Config != tempSkBmpConfig) { |
| tempSkBmp->setConfig(tempSkBmpConfig, hnd->width, hnd->height); |
| tempSkBmp->setPixels((void*)hnd->base); |
| bResult = SkImageEncoder::EncodeFile(sfdumpfile_name, |
| *tempSkBmp, SkImageEncoder::kPNG_Type, 100); |
| LOGE("sfdump: %sDumped Layer[%d] to %s: %s", dumplogstr_png, |
| layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail"); |
| } |
| else { |
| LOGE("sfdump: %sSkipping Layer[%d] dump: Unsupported layer " |
| "format %s for png encoder.", dumplogstr_png, layerIndex, |
| pixelformatstr); |
| } |
| delete tempSkBmp; // Calls SkBitmap::freePixels() internally. |
| } |
| |
| if ((sfdump_counter_raw <= sfdump_countlimit_raw) && hnd->base) { |
| char sfdumpfile_name[256]; |
| bool bResult = false; |
| sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d_%dx%d_%s.raw", |
| sfdumpdir_raw, |
| sfdump_counter_raw, layerIndex, hnd->width, hnd->height, |
| pixelformatstr); |
| FILE* fp = fopen(sfdumpfile_name, "w+"); |
| if (fp != NULL) { |
| bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp); |
| fclose(fp); |
| } |
| LOGE("sfdump: %s Dumped Layer[%d] to %s: %s", dumplogstr_raw, |
| layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail"); |
| } |
| } |
| |
| bool needsAspectRatio (int wRatio, int hRatio) { |
| return ((wRatio != DEFAULT_WIDTH_RATIO) || (hRatio != DEFAULT_HEIGHT_RATIO)); |
| } |
| |
| void applyPixelAspectRatio (int wRatio, int hRatio, int orientation, int maxWidth, |
| int maxHeight, Rect& visibleRect, GLfloat mVertices[][2]) { |
| |
| if ((wRatio == 0) || (hRatio == 0)) |
| return; |
| |
| float wDelta = 0; |
| float hDelta = 0; |
| float aspectRatio; |
| float displayRatio; |
| float new_width, new_height; |
| float old_width = abs(visibleRect.right - visibleRect.left); |
| float old_height = abs(visibleRect.bottom - visibleRect.top); |
| |
| if (orientation == Transform::ROT_INVALID) { |
| // During animation, no defined orientation, rely on mTransformedBounds |
| if (old_width >= old_height) |
| orientation = Transform::ROT_0; |
| else |
| orientation = Transform::ROT_90; |
| } |
| |
| switch (orientation) { |
| |
| case Transform::ROT_0: |
| case Transform::ROT_180: |
| |
| // Calculated Aspect Ratio = Original Aspect Ratio x Pixel Aspect Ratio |
| aspectRatio = (old_width * wRatio) / (old_height * hRatio); |
| displayRatio = (float)maxWidth / (float)maxHeight; |
| |
| if (aspectRatio >= displayRatio) { |
| new_height = old_width / aspectRatio; |
| if (new_height > maxHeight) { |
| new_height = maxHeight; |
| new_width = new_height * aspectRatio; |
| wDelta = (new_width - old_width) / 2; |
| } |
| hDelta = (new_height - old_height) / 2; |
| } else { |
| new_width = old_height * aspectRatio; |
| if (new_width > maxWidth) { |
| new_width = maxWidth; |
| new_height = new_width / aspectRatio; |
| hDelta = (new_height - old_height) / 2; |
| } |
| wDelta = (new_width - old_width) / 2; |
| } |
| |
| if (hDelta != 0) { |
| visibleRect.top -= hDelta; |
| visibleRect.bottom += hDelta; |
| |
| // Set mVertices for GPU fallback (During rotation) |
| if (orientation == Transform::ROT_0) { |
| mVertices[1][1] = mVertices[2][1] = visibleRect.top; |
| mVertices[0][1] = mVertices[3][1] = visibleRect.bottom; |
| } else { |
| mVertices[0][1] = mVertices[3][1] = visibleRect.top; |
| mVertices[1][1] = mVertices[2][1] = visibleRect.bottom; |
| } |
| } |
| |
| if (wDelta != 0) { |
| visibleRect.left -= wDelta; |
| visibleRect.right += wDelta; |
| |
| // Set mVertices for GPU fallback (During rotation) |
| mVertices[0][0] = mVertices[1][0] = visibleRect.left; |
| mVertices[2][0] = mVertices[3][0] = visibleRect.right; |
| } |
| break; |
| |
| case Transform::ROT_90: |
| case Transform::ROT_270: |
| |
| // Calculated Aspect Ratio = Original Aspect Ratio x Pixel Aspect Ratio |
| aspectRatio = (old_height * wRatio) / (old_width * hRatio); |
| displayRatio = (float)maxHeight / (float)maxWidth; |
| |
| if (aspectRatio >= displayRatio) { |
| new_height = old_width * aspectRatio; |
| if (new_height > maxHeight) { |
| new_height = maxHeight; |
| new_width = new_height / aspectRatio; |
| wDelta = (new_width - old_width) / 2; |
| } |
| hDelta = (new_height - old_height) / 2; |
| } else { |
| new_width = old_height / aspectRatio; |
| if (new_width > maxWidth) { |
| new_width = maxWidth; |
| new_height = new_width * aspectRatio; |
| hDelta = (new_height - old_height) / 2; |
| } |
| wDelta = (new_width - old_width) / 2; |
| } |
| |
| if (hDelta != 0) { |
| visibleRect.top -= hDelta; |
| visibleRect.bottom += hDelta; |
| |
| // Set mVertices for GPU fallback (During rotation) |
| if (orientation == Transform::ROT_90) { |
| mVertices[2][1] = mVertices[3][1] = visibleRect.top; |
| mVertices[0][1] = mVertices[1][1] = visibleRect.bottom; |
| } else { |
| mVertices[0][1] = mVertices[1][1] = visibleRect.top; |
| mVertices[2][1] = mVertices[3][1] = visibleRect.bottom; |
| } |
| } |
| |
| if (wDelta != 0) { |
| visibleRect.left -= wDelta; |
| visibleRect.right += wDelta; |
| |
| // Set mVertices for GPU fallback (During rotation) |
| if (orientation == Transform::ROT_90) { |
| mVertices[1][0] = mVertices[2][0] = visibleRect.left; |
| mVertices[0][0] = mVertices[3][0] = visibleRect.right; |
| } else { |
| mVertices[0][0] = mVertices[3][0] = visibleRect.left; |
| mVertices[1][0] = mVertices[2][0] = visibleRect.right; |
| } |
| } |
| break; |
| |
| default: // Handled above. |
| break; |
| |
| } |
| } |
| |
| |