| /* | 
 |  * Copyright (C) 2008 The Android Open Source Project | 
 |  * Copyright (c) 2010 - 2014, 2020 The Linux Foundation. All rights reserved. | 
 |  * | 
 |  * Not a Contribution, Apache license notifications and license are retained | 
 |  * for attribution purposes only. | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include <log/log.h> | 
 |  | 
 | #include <linux/msm_mdp.h> | 
 | #include <linux/fb.h> | 
 |  | 
 | #include <stdint.h> | 
 | #include <string.h> | 
 | #include <unistd.h> | 
 | #include <errno.h> | 
 | #include <fcntl.h> | 
 |  | 
 | #include <sys/ioctl.h> | 
 | #include <sys/types.h> | 
 | #include <sys/mman.h> | 
 |  | 
 | #include <copybit.h> | 
 |  | 
 | #include "gralloc_priv.h" | 
 | #include "software_converter.h" | 
 | #include <qdMetaData.h> | 
 |  | 
 | #define DEBUG_MDP_ERRORS 1 | 
 |  | 
 | /******************************************************************************/ | 
 |  | 
 | #define MAX_SCALE_FACTOR    (4) | 
 | #define MAX_DIMENSION       (4096) | 
 |  | 
 | /******************************************************************************/ | 
 | struct blitReq{ | 
 |     struct  mdp_buf_sync sync; | 
 |     uint32_t count; | 
 |     struct mdp_blit_req req[10]; | 
 | }; | 
 |  | 
 | /** State information for each device instance */ | 
 | struct copybit_context_t { | 
 |     struct copybit_device_t device; | 
 |     int     mFD; | 
 |     uint8_t mAlpha; | 
 |     int     mFlags; | 
 |     bool    mBlitToFB; | 
 |     int     acqFence[MDP_MAX_FENCE_FD]; | 
 |     int     relFence; | 
 |     struct  mdp_buf_sync sync; | 
 |     struct  blitReq list; | 
 |     uint8_t dynamic_fps; | 
 | }; | 
 |  | 
 | /** | 
 |  * Common hardware methods | 
 |  */ | 
 |  | 
 | static int open_copybit(const struct hw_module_t* module, const char* name, | 
 |                         struct hw_device_t** device); | 
 |  | 
 | static struct hw_module_methods_t copybit_module_methods = { | 
 | open:  open_copybit | 
 | }; | 
 |  | 
 | /* | 
 |  * The COPYBIT Module | 
 |  */ | 
 | struct copybit_module_t HAL_MODULE_INFO_SYM = { | 
 | common: { | 
 | tag: HARDWARE_MODULE_TAG, | 
 |      version_major: 1, | 
 |      version_minor: 0, | 
 |      id: COPYBIT_HARDWARE_MODULE_ID, | 
 |      name: "QCT MSM7K COPYBIT Module", | 
 |      author: "Google, Inc.", | 
 |      methods: ©bit_module_methods | 
 |         } | 
 | }; | 
 |  | 
 | /******************************************************************************/ | 
 |  | 
 | /** min of int a, b */ | 
 | static inline int min(int a, int b) { | 
 |     return (a<b) ? a : b; | 
 | } | 
 |  | 
 | /** max of int a, b */ | 
 | static inline int max(int a, int b) { | 
 |     return (a>b) ? a : b; | 
 | } | 
 |  | 
 | /** scale each parameter by mul/div. Assume div isn't 0 */ | 
 | static inline void MULDIV(uint32_t *a, uint32_t *b, int mul, int div) { | 
 |     if (mul != div) { | 
 |         *a = (mul * *a) / div; | 
 |         *b = (mul * *b) / div; | 
 |     } | 
 | } | 
 |  | 
 | /** Determine the intersection of lhs & rhs store in out */ | 
 | static void intersect(struct copybit_rect_t *out, | 
 |                       const struct copybit_rect_t *lhs, | 
 |                       const struct copybit_rect_t *rhs) { | 
 |     out->l = max(lhs->l, rhs->l); | 
 |     out->t = max(lhs->t, rhs->t); | 
 |     out->r = min(lhs->r, rhs->r); | 
 |     out->b = min(lhs->b, rhs->b); | 
 | } | 
 |  | 
 | static bool validateCopybitRect(struct copybit_rect_t *rect) { | 
 |     return ((rect->b > rect->t) && (rect->r > rect->l)) ; | 
 | } | 
 |  | 
 | /** convert COPYBIT_FORMAT to MDP format */ | 
 | static int get_format(int format) { | 
 |     switch (format) { | 
 |         case HAL_PIXEL_FORMAT_RGB_565:       return MDP_RGB_565; | 
 |         case HAL_PIXEL_FORMAT_RGBA_5551:     return MDP_RGBA_5551; | 
 |         case HAL_PIXEL_FORMAT_RGBA_4444:     return MDP_RGBA_4444; | 
 |         case HAL_PIXEL_FORMAT_RGBX_8888:     return MDP_RGBX_8888; | 
 |         case HAL_PIXEL_FORMAT_BGRX_8888:     return MDP_BGRX_8888; | 
 |         case HAL_PIXEL_FORMAT_RGB_888:       return MDP_RGB_888; | 
 |         case HAL_PIXEL_FORMAT_RGBA_8888:     return MDP_RGBA_8888; | 
 |         case HAL_PIXEL_FORMAT_BGRA_8888:     return MDP_BGRA_8888; | 
 |         case HAL_PIXEL_FORMAT_YCrCb_422_I:   return MDP_YCRYCB_H2V1; | 
 |         case HAL_PIXEL_FORMAT_YCbCr_422_I:   return MDP_YCBYCR_H2V1; | 
 |         case HAL_PIXEL_FORMAT_YCrCb_422_SP:  return MDP_Y_CRCB_H2V1; | 
 |         case HAL_PIXEL_FORMAT_YCrCb_420_SP:  return MDP_Y_CRCB_H2V2; | 
 |         case HAL_PIXEL_FORMAT_YCbCr_422_SP:  return MDP_Y_CBCR_H2V1; | 
 |         case HAL_PIXEL_FORMAT_YCbCr_420_SP:  return MDP_Y_CBCR_H2V2; | 
 |         case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: return MDP_Y_CBCR_H2V2_ADRENO; | 
 |         case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: return MDP_Y_CBCR_H2V2_VENUS; | 
 |         case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: return MDP_Y_CRCB_H2V2_VENUS; | 
 |         case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: return MDP_Y_CBCR_H2V2; | 
 |         case HAL_PIXEL_FORMAT_CbYCrY_422_I: return MDP_CBYCRY_H2V1; | 
 |         case HAL_PIXEL_FORMAT_BGR_888: return MDP_BGR_888; | 
 |     } | 
 |     return -1; | 
 | } | 
 |  | 
 | /** convert from copybit image to mdp image structure */ | 
 | static void set_image(struct mdp_img *img, const struct copybit_image_t *rhs) | 
 | { | 
 |     private_handle_t* hnd = (private_handle_t*)rhs->handle; | 
 |     if(hnd == NULL){ | 
 |         ALOGE("copybit: Invalid handle"); | 
 |         return; | 
 |     } | 
 |     img->width      = rhs->w; | 
 |     img->height     = rhs->h; | 
 |     img->format     = get_format(rhs->format); | 
 |     img->offset     = (uint32_t)hnd->offset; | 
 |     img->memory_id  = hnd->fd; | 
 | } | 
 | /** setup rectangles */ | 
 | static bool set_rects(struct copybit_context_t *dev, | 
 |                       struct mdp_blit_req *e, | 
 |                       const struct copybit_rect_t *dst, | 
 |                       const struct copybit_rect_t *src, | 
 |                       const struct copybit_rect_t *scissor) { | 
 |     struct copybit_rect_t clip; | 
 |     intersect(&clip, scissor, dst); | 
 |  | 
 |     if (!validateCopybitRect(&clip)) | 
 |        return false; | 
 |  | 
 |     e->dst_rect.x  = clip.l; | 
 |     e->dst_rect.y  = clip.t; | 
 |     e->dst_rect.w  = clip.r - clip.l; | 
 |     e->dst_rect.h  = clip.b - clip.t; | 
 |  | 
 |     uint32_t W, H, delta_x, delta_y; | 
 |     if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) { | 
 |         delta_x = (clip.t - dst->t); | 
 |         delta_y = (dst->r - clip.r); | 
 |         e->src_rect.w = (clip.b - clip.t); | 
 |         e->src_rect.h = (clip.r - clip.l); | 
 |         W = dst->b - dst->t; | 
 |         H = dst->r - dst->l; | 
 |     } else { | 
 |         delta_x  = (clip.l - dst->l); | 
 |         delta_y  = (clip.t - dst->t); | 
 |         e->src_rect.w  = (clip.r - clip.l); | 
 |         e->src_rect.h  = (clip.b - clip.t); | 
 |         W = dst->r - dst->l; | 
 |         H = dst->b - dst->t; | 
 |     } | 
 |  | 
 |     MULDIV(&delta_x, &e->src_rect.w, src->r - src->l, W); | 
 |     MULDIV(&delta_y, &e->src_rect.h, src->b - src->t, H); | 
 |  | 
 |     e->src_rect.x = delta_x + src->l; | 
 |     e->src_rect.y = delta_y + src->t; | 
 |  | 
 |     if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_V) { | 
 |         if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) { | 
 |             e->src_rect.x = (src->l + src->r) - (e->src_rect.x + e->src_rect.w); | 
 |         }else{ | 
 |             e->src_rect.y = (src->t + src->b) - (e->src_rect.y + e->src_rect.h); | 
 |         } | 
 |     } | 
 |  | 
 |     if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_H) { | 
 |         if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) { | 
 |             e->src_rect.y = (src->t + src->b) - (e->src_rect.y + e->src_rect.h); | 
 |         }else{ | 
 |             e->src_rect.x = (src->l + src->r) - (e->src_rect.x + e->src_rect.w); | 
 |         } | 
 |     } | 
 |     return true; | 
 | } | 
 |  | 
 | /** setup mdp request */ | 
 | static void set_infos(struct copybit_context_t *dev, | 
 |                       struct mdp_blit_req *req, int flags) | 
 | { | 
 |     req->alpha = dev->mAlpha; | 
 |     req->fps = dev->dynamic_fps; | 
 |     req->transp_mask = MDP_TRANSP_NOP; | 
 |     req->flags = dev->mFlags | flags; | 
 |     // check if we are blitting to f/b | 
 |     if (COPYBIT_ENABLE == dev->mBlitToFB) { | 
 |         req->flags |= MDP_MEMORY_ID_TYPE_FB; | 
 |     } | 
 | #if defined(COPYBIT_QSD8K) | 
 |     req->flags |= MDP_BLEND_FG_PREMULT; | 
 | #endif | 
 | } | 
 |  | 
 | /** copy the bits */ | 
 | static int msm_copybit(struct copybit_context_t *dev, void const *list) | 
 | { | 
 |     int err; | 
 |     if (dev->relFence != -1) { | 
 |         close(dev->relFence); | 
 |         dev->relFence = -1; | 
 |     } | 
 |     err = ioctl(dev->mFD, MSMFB_ASYNC_BLIT, | 
 |                     (struct mdp_async_blit_req_list const*)list); | 
 |     ALOGE_IF(err<0, "copyBits failed (%s)", strerror(errno)); | 
 |     if (err == 0) { | 
 |         return 0; | 
 |     } else { | 
 | #if DEBUG_MDP_ERRORS | 
 |         struct mdp_async_blit_req_list const* l = | 
 |             (struct mdp_async_blit_req_list const*)list; | 
 |         for (unsigned int i=0 ; i<l->count ; i++) { | 
 |             ALOGE("%d: src={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n" | 
 |                   "    dst={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n" | 
 |                   "    flags=%08x, fps=%d" | 
 |                   , | 
 |                   i, | 
 |                   l->req[i].src.width, | 
 |                   l->req[i].src.height, | 
 |                   l->req[i].src.format, | 
 |                   l->req[i].src_rect.x, | 
 |                   l->req[i].src_rect.y, | 
 |                   l->req[i].src_rect.w, | 
 |                   l->req[i].src_rect.h, | 
 |                   l->req[i].dst.width, | 
 |                   l->req[i].dst.height, | 
 |                   l->req[i].dst.format, | 
 |                   l->req[i].dst_rect.x, | 
 |                   l->req[i].dst_rect.y, | 
 |                   l->req[i].dst_rect.w, | 
 |                   l->req[i].dst_rect.h, | 
 |                   l->req[i].flags, | 
 |                   l->req[i].fps | 
 |                  ); | 
 |         } | 
 | #endif | 
 |         return -errno; | 
 |     } | 
 | } | 
 |  | 
 | /*****************************************************************************/ | 
 |  | 
 | /** Set a parameter to value */ | 
 | static int set_parameter_copybit( | 
 |     struct copybit_device_t *dev, | 
 |     int name, | 
 |     int value) | 
 | { | 
 |     struct copybit_context_t* ctx = (struct copybit_context_t*)dev; | 
 |     int status = 0; | 
 |     if (ctx) { | 
 |         switch(name) { | 
 |             case COPYBIT_ROTATION_DEG: | 
 |                 switch (value) { | 
 |                     case 0: | 
 |                         ctx->mFlags &= ~0x7; | 
 |                         break; | 
 |                     case 90: | 
 |                         ctx->mFlags &= ~0x7; | 
 |                         ctx->mFlags |= MDP_ROT_90; | 
 |                         break; | 
 |                     case 180: | 
 |                         ctx->mFlags &= ~0x7; | 
 |                         ctx->mFlags |= MDP_ROT_180; | 
 |                         break; | 
 |                     case 270: | 
 |                         ctx->mFlags &= ~0x7; | 
 |                         ctx->mFlags |= MDP_ROT_270; | 
 |                         break; | 
 |                     default: | 
 |                         ALOGE("Invalid value for COPYBIT_ROTATION_DEG"); | 
 |                         status = -EINVAL; | 
 |                         break; | 
 |                 } | 
 |                 break; | 
 |             case COPYBIT_PLANE_ALPHA: | 
 |                 if (value < 0)      value = MDP_ALPHA_NOP; | 
 |                 if (value >= 256)   value = 255; | 
 |                 ctx->mAlpha = (uint8_t)value; | 
 |                 break; | 
 |             case COPYBIT_DYNAMIC_FPS: | 
 |                 ctx->dynamic_fps = (uint8_t)value; | 
 |                 break; | 
 |             case COPYBIT_DITHER: | 
 |                 if (value == COPYBIT_ENABLE) { | 
 |                     ctx->mFlags |= MDP_DITHER; | 
 |                 } else if (value == COPYBIT_DISABLE) { | 
 |                     ctx->mFlags &= ~MDP_DITHER; | 
 |                 } | 
 |                 break; | 
 |             case COPYBIT_BLUR: | 
 |                 if (value == COPYBIT_ENABLE) { | 
 |                     ctx->mFlags |= MDP_BLUR; | 
 |                 } else if (value == COPYBIT_DISABLE) { | 
 |                     ctx->mFlags &= ~MDP_BLUR; | 
 |                 } | 
 |                 break; | 
 |             case COPYBIT_BLEND_MODE: | 
 |                 if(value == COPYBIT_BLENDING_PREMULT) { | 
 |                     ctx->mFlags |= MDP_BLEND_FG_PREMULT; | 
 |                 } else { | 
 |                     ctx->mFlags &= ~MDP_BLEND_FG_PREMULT; | 
 |                 } | 
 |                 break; | 
 |             case COPYBIT_TRANSFORM: | 
 |                 ctx->mFlags &= ~0x7; | 
 |                 ctx->mFlags |= value & 0x7; | 
 |                 break; | 
 |             case COPYBIT_BLIT_TO_FRAMEBUFFER: | 
 |                 if (COPYBIT_ENABLE == value) { | 
 |                     ctx->mBlitToFB = value; | 
 |                 } else if (COPYBIT_DISABLE == value) { | 
 |                     ctx->mBlitToFB = value; | 
 |                 } else { | 
 |                     ALOGE ("%s:Invalid input for COPYBIT_BLIT_TO_FRAMEBUFFER : %d", | 
 |                             __FUNCTION__, value); | 
 |                 } | 
 |                 break; | 
 |             case COPYBIT_FG_LAYER: | 
 |                 if(value == COPYBIT_ENABLE) { | 
 |                      ctx->mFlags |= MDP_IS_FG; | 
 |                 } else if (value == COPYBIT_DISABLE) { | 
 |                     ctx->mFlags &= ~MDP_IS_FG; | 
 |                 } | 
 |                 break ; | 
 |             default: | 
 |                 status = -EINVAL; | 
 |                 break; | 
 |         } | 
 |     } else { | 
 |         status = -EINVAL; | 
 |     } | 
 |     return status; | 
 | } | 
 |  | 
 | /** Get a static info value */ | 
 | static int get(struct copybit_device_t *dev, int name) | 
 | { | 
 |     struct copybit_context_t* ctx = (struct copybit_context_t*)dev; | 
 |     int value; | 
 |     if (ctx) { | 
 |         switch(name) { | 
 |             case COPYBIT_MINIFICATION_LIMIT: | 
 |                 value = MAX_SCALE_FACTOR; | 
 |                 break; | 
 |             case COPYBIT_MAGNIFICATION_LIMIT: | 
 |                 value = MAX_SCALE_FACTOR; | 
 |                 break; | 
 |             case COPYBIT_SCALING_FRAC_BITS: | 
 |                 value = 32; | 
 |                 break; | 
 |             case COPYBIT_ROTATION_STEP_DEG: | 
 |                 value = 90; | 
 |                 break; | 
 |             default: | 
 |                 value = -EINVAL; | 
 |         } | 
 |     } else { | 
 |         value = -EINVAL; | 
 |     } | 
 |     return value; | 
 | } | 
 |  | 
 | static int set_sync_copybit(struct copybit_device_t *dev, | 
 |     int acquireFenceFd) | 
 | { | 
 |     struct copybit_context_t* ctx = (struct copybit_context_t*)dev; | 
 |     if (acquireFenceFd != -1) { | 
 |         if (ctx->list.sync.acq_fen_fd_cnt < (MDP_MAX_FENCE_FD - 1)) { | 
 |             ctx->acqFence[ctx->list.sync.acq_fen_fd_cnt++] = acquireFenceFd; | 
 |         } else { | 
 |             int ret = -EINVAL; | 
 |             struct blitReq *list = &ctx->list; | 
 |  | 
 |             // Since fence is full kick off what is already in the list | 
 |             ret = msm_copybit(ctx, list); | 
 |             if (ret < 0) { | 
 |                 ALOGE("%s: Blit call failed", __FUNCTION__); | 
 |                 return -EINVAL; | 
 |             } | 
 |             list->count = 0; | 
 |             list->sync.acq_fen_fd_cnt = 0; | 
 |             ctx->acqFence[list->sync.acq_fen_fd_cnt++] = acquireFenceFd; | 
 |         } | 
 |     } | 
 |     return 0; | 
 | } | 
 |  | 
 | /** do a stretch blit type operation */ | 
 | static int stretch_copybit( | 
 |     struct copybit_device_t *dev, | 
 |     struct copybit_image_t const *dst, | 
 |     struct copybit_image_t const *src, | 
 |     struct copybit_rect_t const *dst_rect, | 
 |     struct copybit_rect_t const *src_rect, | 
 |     struct copybit_region_t const *region) | 
 | { | 
 |     struct copybit_context_t* ctx = (struct copybit_context_t*)dev; | 
 |     struct blitReq *list; | 
 |     int status = 0; | 
 |     private_handle_t *yv12_handle = NULL; | 
 |  | 
 |     if (ctx) { | 
 |         list = &ctx->list; | 
 |  | 
 |         if (ctx->mAlpha < 255) { | 
 |             switch (src->format) { | 
 |                 // we don't support plane alpha with RGBA formats | 
 |                 case HAL_PIXEL_FORMAT_RGBA_8888: | 
 |                 case HAL_PIXEL_FORMAT_BGRA_8888: | 
 |                 case HAL_PIXEL_FORMAT_RGBA_5551: | 
 |                 case HAL_PIXEL_FORMAT_RGBA_4444: | 
 |                     ALOGE ("%s : Unsupported Pixel format %d", __FUNCTION__, | 
 |                            src->format); | 
 |                     return -EINVAL; | 
 |             } | 
 |         } | 
 |  | 
 |         if (src_rect->l < 0 || (uint32_t)src_rect->r > src->w || | 
 |             src_rect->t < 0 || (uint32_t)src_rect->b > src->h) { | 
 |             // this is always invalid | 
 |             ALOGE ("%s : Invalid source rectangle : src_rect l %d t %d r %d b %d",\ | 
 |                    __FUNCTION__, src_rect->l, src_rect->t, src_rect->r, src_rect->b); | 
 |  | 
 |             return -EINVAL; | 
 |         } | 
 |  | 
 |         if (src->w > MAX_DIMENSION || src->h > MAX_DIMENSION) { | 
 |             ALOGE ("%s : Invalid source dimensions w %d h %d", __FUNCTION__, src->w, src->h); | 
 |             return -EINVAL; | 
 |         } | 
 |  | 
 |         if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION) { | 
 |             ALOGE ("%s : Invalid DST dimensions w %d h %d", __FUNCTION__, dst->w, dst->h); | 
 |             return -EINVAL; | 
 |         } | 
 |  | 
 |         if(src->format ==  HAL_PIXEL_FORMAT_YV12) { | 
 |             int usage = | 
 |             GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | GRALLOC_USAGE_PRIVATE_UNCACHED; | 
 |             if (0 == alloc_buffer(&yv12_handle,src->w,src->h, | 
 |                                   src->format, usage)){ | 
 |                 if(0 == convertYV12toYCrCb420SP(src,yv12_handle)){ | 
 |                     (const_cast<copybit_image_t *>(src))->format = | 
 |                         HAL_PIXEL_FORMAT_YCrCb_420_SP; | 
 |                     (const_cast<copybit_image_t *>(src))->handle = | 
 |                         yv12_handle; | 
 |                     (const_cast<copybit_image_t *>(src))->base = | 
 |                         (void *)yv12_handle->base; | 
 |                 } | 
 |                 else{ | 
 |                     ALOGE("Error copybit conversion from yv12 failed"); | 
 |                     if(yv12_handle) | 
 |                         free_buffer(yv12_handle); | 
 |                     return -EINVAL; | 
 |                 } | 
 |             } | 
 |             else{ | 
 |                 ALOGE("Error:unable to allocate memeory for yv12 software conversion"); | 
 |                 return -EINVAL; | 
 |             } | 
 |         } | 
 |         const uint32_t maxCount = | 
 |                 (uint32_t)(sizeof(list->req)/sizeof(list->req[0])); | 
 |         const struct copybit_rect_t bounds = { 0, 0, (int)dst->w, (int)dst->h }; | 
 |         struct copybit_rect_t clip; | 
 |         status = 0; | 
 |         while ((status == 0) && region->next(region, &clip)) { | 
 |             intersect(&clip, &bounds, &clip); | 
 |             mdp_blit_req* req = &list->req[list->count]; | 
 |             int flags = 0; | 
 |  | 
 |             private_handle_t* src_hnd = (private_handle_t*)src->handle; | 
 |             if(src_hnd != NULL && | 
 |                 (!(src_hnd->flags & private_handle_t::PRIV_FLAGS_CACHED))) { | 
 |                 flags |=  MDP_BLIT_NON_CACHED; | 
 |             } | 
 |  | 
 |             // Set Color Space for MDP to configure CSC matrix | 
 |             req->color_space = ITU_R_601; | 
 |  | 
 |             set_infos(ctx, req, flags); | 
 |             set_image(&req->dst, dst); | 
 |             set_image(&req->src, src); | 
 |             if (set_rects(ctx, req, dst_rect, src_rect, &clip) == false) | 
 |                 continue; | 
 |  | 
 |             if (req->src_rect.w<=0 || req->src_rect.h<=0) | 
 |                 continue; | 
 |  | 
 |             if (req->dst_rect.w<=0 || req->dst_rect.h<=0) | 
 |                 continue; | 
 |  | 
 |             if (++list->count == maxCount) { | 
 |                 status = msm_copybit(ctx, list); | 
 |                 list->sync.acq_fen_fd_cnt = 0; | 
 |                 list->count = 0; | 
 |             } | 
 |         } | 
 |         if(yv12_handle) { | 
 |             //Before freeing the buffer we need buffer passed through blit call | 
 |             if (list->count != 0) { | 
 |                 status = msm_copybit(ctx, list); | 
 |                 list->sync.acq_fen_fd_cnt = 0; | 
 |                 list->count = 0; | 
 |             } | 
 |             free_buffer(yv12_handle); | 
 |         } | 
 |     } else { | 
 |         ALOGE ("%s : Invalid COPYBIT context", __FUNCTION__); | 
 |         status = -EINVAL; | 
 |     } | 
 |     return status; | 
 | } | 
 |  | 
 | /** Perform a blit type operation */ | 
 | static int blit_copybit( | 
 |     struct copybit_device_t *dev, | 
 |     struct copybit_image_t const *dst, | 
 |     struct copybit_image_t const *src, | 
 |     struct copybit_region_t const *region) | 
 | { | 
 |     struct copybit_rect_t dr = { 0, 0, (int)dst->w, (int)dst->h }; | 
 |     struct copybit_rect_t sr = { 0, 0, (int)src->w, (int)src->h }; | 
 |     return stretch_copybit(dev, dst, src, &dr, &sr, region); | 
 | } | 
 |  | 
 | static int finish_copybit(struct copybit_device_t *dev) | 
 | { | 
 |     // NOP for MDP copybit | 
 |     if(!dev) | 
 |        return -EINVAL; | 
 |  | 
 |     return 0; | 
 | } | 
 | static int clear_copybit(struct copybit_device_t *dev, | 
 |                          struct copybit_image_t const *buf, | 
 |                          struct copybit_rect_t *rect) | 
 | { | 
 |     struct copybit_context_t* ctx = (struct copybit_context_t*)dev; | 
 |     uint32_t color = 0; // black color | 
 |  | 
 |     if (!ctx) { | 
 |         ALOGE ("%s: Invalid copybit context", __FUNCTION__); | 
 |         return -EINVAL; | 
 |     } | 
 |  | 
 |     struct blitReq list1; | 
 |     memset((char *)&list1 , 0 ,sizeof (struct blitReq) ); | 
 |     list1.count = 1; | 
 |     int my_tmp_get_fence = -1; | 
 |  | 
 |     list1.sync.acq_fen_fd  =  ctx->acqFence; | 
 |     list1.sync.rel_fen_fd  =  &my_tmp_get_fence; | 
 |     list1.sync.acq_fen_fd_cnt = ctx->list.sync.acq_fen_fd_cnt; | 
 |     mdp_blit_req* req = &list1.req[0]; | 
 |  | 
 |     if(!req) { | 
 |         ALOGE ("%s : Invalid request", __FUNCTION__); | 
 |         return -EINVAL; | 
 |     } | 
 |  | 
 |     set_image(&req->dst, buf); | 
 |     set_image(&req->src, buf); | 
 |  | 
 |     if (rect->l < 0 || (uint32_t)(rect->r - rect->l) > req->dst.width || | 
 |        rect->t < 0 || (uint32_t)(rect->b - rect->t) > req->dst.height) { | 
 |        ALOGE ("%s : Invalid rect : src_rect l %d t %d r %d b %d",\ | 
 |        __FUNCTION__, rect->l, rect->t, rect->r, rect->b); | 
 |        return -EINVAL; | 
 |     } | 
 |  | 
 |     req->dst_rect.x  = rect->l; | 
 |     req->dst_rect.y  = rect->t; | 
 |     req->dst_rect.w  = rect->r - rect->l; | 
 |     req->dst_rect.h  = rect->b - rect->t; | 
 |  | 
 |     req->src_rect = req->dst_rect; | 
 |  | 
 |     req->const_color.b = (uint32_t)((color >> 16) & 0xff); | 
 |     req->const_color.g = (uint32_t)((color >> 8) & 0xff); | 
 |     req->const_color.r = (uint32_t)((color >> 0) & 0xff); | 
 |     req->const_color.alpha = MDP_ALPHA_NOP; | 
 |  | 
 |     req->transp_mask = MDP_TRANSP_NOP; | 
 |     req->flags = MDP_SOLID_FILL | MDP_MEMORY_ID_TYPE_FB | MDP_BLEND_FG_PREMULT; | 
 |     int status = msm_copybit(ctx, &list1); | 
 |  | 
 |     ctx->list.sync.acq_fen_fd_cnt = 0; | 
 |     if (my_tmp_get_fence !=  -1) | 
 |         close(my_tmp_get_fence); | 
 |  | 
 |     return status; | 
 | } | 
 |  | 
 | /** Fill the rect on dst with RGBA color **/ | 
 | static int fill_color(struct copybit_device_t *dev, | 
 |                       struct copybit_image_t const *dst, | 
 |                       struct copybit_rect_t const *rect, | 
 |                       uint32_t color) | 
 | { | 
 |     struct copybit_context_t* ctx = (struct copybit_context_t*)dev; | 
 |     if (!ctx) { | 
 |         ALOGE("%s: Invalid copybit context", __FUNCTION__); | 
 |         return -EINVAL; | 
 |     } | 
 |  | 
 |     if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION) { | 
 |         ALOGE("%s: Invalid DST w=%d h=%d", __FUNCTION__, dst->w, dst->h); | 
 |         return -EINVAL; | 
 |     } | 
 |  | 
 |     if (rect->l < 0 || (uint32_t)(rect->r - rect->l) > dst->w || | 
 |         rect->t < 0 || (uint32_t)(rect->b - rect->t) > dst->h) { | 
 |         ALOGE("%s: Invalid destination rect: l=%d t=%d r=%d b=%d", | 
 |                 __FUNCTION__, rect->l, rect->t, rect->r, rect->b); | 
 |         return -EINVAL; | 
 |     } | 
 |  | 
 |     int status = 0; | 
 |     struct blitReq* list = &ctx->list; | 
 |     mdp_blit_req* req = &list->req[list->count++]; | 
 |     set_infos(ctx, req, MDP_SOLID_FILL); | 
 |     set_image(&req->src, dst); | 
 |     set_image(&req->dst, dst); | 
 |  | 
 |     req->dst_rect.x = rect->l; | 
 |     req->dst_rect.y = rect->t; | 
 |     req->dst_rect.w = rect->r - rect->l; | 
 |     req->dst_rect.h = rect->b - rect->t; | 
 |     req->src_rect = req->dst_rect; | 
 |  | 
 |     req->const_color.r = (uint32_t)((color >> 0) & 0xff); | 
 |     req->const_color.g = (uint32_t)((color >> 8) & 0xff); | 
 |     req->const_color.b = (uint32_t)((color >> 16) & 0xff); | 
 |     req->const_color.alpha = (uint32_t)((color >> 24) & 0xff); | 
 |  | 
 |     if (list->count == sizeof(list->req)/sizeof(list->req[0])) { | 
 |         status = msm_copybit(ctx, list); | 
 |         list->sync.acq_fen_fd_cnt = 0; | 
 |         list->count = 0; | 
 |     } | 
 |     return status; | 
 | } | 
 |  | 
 | /*****************************************************************************/ | 
 |  | 
 | /** Close the copybit device */ | 
 | static int close_copybit(struct hw_device_t *dev) | 
 | { | 
 |     struct copybit_context_t* ctx = (struct copybit_context_t*)dev; | 
 |     if (ctx) { | 
 |         close(ctx->mFD); | 
 |         free(ctx); | 
 |     } | 
 |     return 0; | 
 | } | 
 |  | 
 | static int flush_get_fence(struct copybit_device_t *dev, int* fd) | 
 | { | 
 |     struct copybit_context_t* ctx = (struct copybit_context_t*)dev; | 
 |     struct blitReq *list = &ctx->list; | 
 |     int ret = -EINVAL; | 
 |  | 
 |     if (list->count) { | 
 |         ret = msm_copybit(ctx, list); | 
 |         if (ret < 0) | 
 |             ALOGE("%s: Blit call failed", __FUNCTION__); | 
 |         list->count = 0; | 
 |     } | 
 |     *fd = ctx->relFence; | 
 |     list->sync.acq_fen_fd_cnt = 0; | 
 |     ctx->relFence = -1; | 
 |     return ret; | 
 | } | 
 |  | 
 | /** Open a new instance of a copybit device using name */ | 
 | static int open_copybit(const struct hw_module_t* module, const char* name, | 
 |                         struct hw_device_t** device) | 
 | { | 
 |     int status = -EINVAL; | 
 |  | 
 |     if (strcmp(name, COPYBIT_HARDWARE_COPYBIT0)) { | 
 |         return COPYBIT_FAILURE; | 
 |     } | 
 |     copybit_context_t *ctx; | 
 |     ctx = (copybit_context_t *)malloc(sizeof(copybit_context_t)); | 
 |  | 
 |     if (ctx == NULL ) { | 
 |        return COPYBIT_FAILURE; | 
 |     } | 
 |  | 
 |     memset(ctx, 0, sizeof(*ctx)); | 
 |  | 
 |     ctx->device.common.tag = HARDWARE_DEVICE_TAG; | 
 |     ctx->device.common.version = 1; | 
 |     ctx->device.common.module = const_cast<hw_module_t*>(module); | 
 |     ctx->device.common.close = close_copybit; | 
 |     ctx->device.set_parameter = set_parameter_copybit; | 
 |     ctx->device.get = get; | 
 |     ctx->device.blit = blit_copybit; | 
 |     ctx->device.set_sync = set_sync_copybit; | 
 |     ctx->device.stretch = stretch_copybit; | 
 |     ctx->device.finish = finish_copybit; | 
 |     ctx->device.fill_color = fill_color; | 
 |     ctx->device.flush_get_fence = flush_get_fence; | 
 |     ctx->device.clear = clear_copybit; | 
 |     ctx->mAlpha = MDP_ALPHA_NOP; | 
 |     //dynamic_fps is zero means default | 
 |     //panel refresh rate for driver. | 
 |     ctx->dynamic_fps = 0; | 
 |     ctx->mFlags = 0; | 
 |     ctx->sync.flags = 0; | 
 |     ctx->relFence = -1; | 
 |     for (int i=0; i < MDP_MAX_FENCE_FD; i++) { | 
 |         ctx->acqFence[i] = -1; | 
 |     } | 
 |     ctx->sync.acq_fen_fd = ctx->acqFence; | 
 |     ctx->sync.rel_fen_fd = &ctx->relFence; | 
 |     ctx->list.count = 0; | 
 |     ctx->list.sync.acq_fen_fd_cnt = 0; | 
 |     ctx->list.sync.rel_fen_fd = ctx->sync.rel_fen_fd; | 
 |     ctx->list.sync.acq_fen_fd = ctx->sync.acq_fen_fd; | 
 |     ctx->mFD = open("/dev/graphics/fb0", O_RDWR, 0); | 
 |     if (ctx->mFD < 0) { | 
 |         status = errno; | 
 |         ALOGE("Error opening frame buffer errno=%d (%s)", | 
 |               status, strerror(status)); | 
 |         status = -status; | 
 |     } else { | 
 |         status = 0; | 
 |         *device = &ctx->device.common; | 
 |     } | 
 |     return status; | 
 | } |