Home | History | Annotate | Download | only in libcopybit
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 
     18 #define LOG_TAG "copybit"
     19 
     20 #include <cutils/log.h>
     21 
     22 #include <linux/msm_mdp.h>
     23 #include <linux/fb.h>
     24 
     25 #include <stdint.h>
     26 #include <string.h>
     27 #include <unistd.h>
     28 #include <errno.h>
     29 #include <fcntl.h>
     30 
     31 #include <sys/ioctl.h>
     32 #include <sys/types.h>
     33 #include <sys/mman.h>
     34 
     35 #include <hardware/copybit.h>
     36 
     37 #include "gralloc_priv.h"
     38 
     39 #define DEBUG_MDP_ERRORS 1
     40 
     41 /******************************************************************************/
     42 
     43 #if defined(COPYBIT_MSM7K)
     44 #define MAX_SCALE_FACTOR    (4)
     45 #define MAX_DIMENSION       (4096)
     46 #elif defined(COPYBIT_QSD8K)
     47 #define MAX_SCALE_FACTOR    (8)
     48 #define MAX_DIMENSION       (2048)
     49 #else
     50 #error "Unsupported MDP version"
     51 #endif
     52 
     53 /******************************************************************************/
     54 
     55 /** State information for each device instance */
     56 struct copybit_context_t {
     57     struct copybit_device_t device;
     58     int     mFD;
     59     uint8_t mAlpha;
     60     uint8_t mFlags;
     61 };
     62 
     63 /**
     64  * Common hardware methods
     65  */
     66 
     67 static int open_copybit(const struct hw_module_t* module, const char* name,
     68         struct hw_device_t** device);
     69 
     70 static struct hw_module_methods_t copybit_module_methods = {
     71     open:  open_copybit
     72 };
     73 
     74 /*
     75  * The COPYBIT Module
     76  */
     77 struct copybit_module_t HAL_MODULE_INFO_SYM = {
     78     common: {
     79         tag: HARDWARE_MODULE_TAG,
     80         version_major: 1,
     81         version_minor: 0,
     82         id: COPYBIT_HARDWARE_MODULE_ID,
     83         name: "QCT MSM7K COPYBIT Module",
     84         author: "Google, Inc.",
     85         methods: &copybit_module_methods
     86     }
     87 };
     88 
     89 /******************************************************************************/
     90 
     91 /** min of int a, b */
     92 static inline int min(int a, int b) {
     93     return (a<b) ? a : b;
     94 }
     95 
     96 /** max of int a, b */
     97 static inline int max(int a, int b) {
     98     return (a>b) ? a : b;
     99 }
    100 
    101 /** scale each parameter by mul/div. Assume div isn't 0 */
    102 static inline void MULDIV(uint32_t *a, uint32_t *b, int mul, int div) {
    103     if (mul != div) {
    104         *a = (mul * *a) / div;
    105         *b = (mul * *b) / div;
    106     }
    107 }
    108 
    109 /** Determine the intersection of lhs & rhs store in out */
    110 static void intersect(struct copybit_rect_t *out,
    111                       const struct copybit_rect_t *lhs,
    112                       const struct copybit_rect_t *rhs) {
    113     out->l = max(lhs->l, rhs->l);
    114     out->t = max(lhs->t, rhs->t);
    115     out->r = min(lhs->r, rhs->r);
    116     out->b = min(lhs->b, rhs->b);
    117 }
    118 
    119 /** convert COPYBIT_FORMAT to MDP format */
    120 static int get_format(int format) {
    121     switch (format) {
    122     case COPYBIT_FORMAT_RGB_565:       return MDP_RGB_565;
    123     case COPYBIT_FORMAT_RGBX_8888:     return MDP_RGBX_8888;
    124     case COPYBIT_FORMAT_RGB_888:       return MDP_RGB_888;
    125     case COPYBIT_FORMAT_RGBA_8888:     return MDP_RGBA_8888;
    126     case COPYBIT_FORMAT_BGRA_8888:     return MDP_BGRA_8888;
    127     case COPYBIT_FORMAT_YCrCb_420_SP:  return MDP_Y_CBCR_H2V2;
    128     case COPYBIT_FORMAT_YCbCr_422_SP:  return MDP_Y_CRCB_H2V1;
    129     }
    130     return -1;
    131 }
    132 
    133 /** convert from copybit image to mdp image structure */
    134 static void set_image(struct mdp_img *img, const struct copybit_image_t *rhs)
    135 {
    136     private_handle_t* hnd = (private_handle_t*)rhs->handle;
    137     img->width      = rhs->w;
    138     img->height     = rhs->h;
    139     img->format     = get_format(rhs->format);
    140     img->offset     = hnd->offset;
    141 #if defined(COPYBIT_MSM7K)
    142     if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_GPU) {
    143         img->offset += hnd->map_offset;
    144         img->memory_id = hnd->gpu_fd;
    145         if (img->format == MDP_RGBA_8888) {
    146             // msm7201A GPU only supports BGRA_8888 destinations
    147             img->format = MDP_BGRA_8888;
    148         }
    149     } else {
    150         img->memory_id = hnd->fd;
    151     }
    152 #else
    153     img->memory_id  = hnd->fd;
    154 #endif
    155 }
    156 /** setup rectangles */
    157 static void set_rects(struct copybit_context_t *dev,
    158                       struct mdp_blit_req *e,
    159                       const struct copybit_rect_t *dst,
    160                       const struct copybit_rect_t *src,
    161                       const struct copybit_rect_t *scissor) {
    162     struct copybit_rect_t clip;
    163     intersect(&clip, scissor, dst);
    164 
    165     e->dst_rect.x  = clip.l;
    166     e->dst_rect.y  = clip.t;
    167     e->dst_rect.w  = clip.r - clip.l;
    168     e->dst_rect.h  = clip.b - clip.t;
    169 
    170     uint32_t W, H;
    171     if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) {
    172         e->src_rect.x = (clip.t - dst->t) + src->t;
    173         e->src_rect.y = (dst->r - clip.r) + src->l;
    174         e->src_rect.w = (clip.b - clip.t);
    175         e->src_rect.h = (clip.r - clip.l);
    176         W = dst->b - dst->t;
    177         H = dst->r - dst->l;
    178     } else {
    179         e->src_rect.x  = (clip.l - dst->l) + src->l;
    180         e->src_rect.y  = (clip.t - dst->t) + src->t;
    181         e->src_rect.w  = (clip.r - clip.l);
    182         e->src_rect.h  = (clip.b - clip.t);
    183         W = dst->r - dst->l;
    184         H = dst->b - dst->t;
    185     }
    186     MULDIV(&e->src_rect.x, &e->src_rect.w, src->r - src->l, W);
    187     MULDIV(&e->src_rect.y, &e->src_rect.h, src->b - src->t, H);
    188     if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_V) {
    189         e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h);
    190     }
    191     if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_H) {
    192         e->src_rect.x = e->src.width  - (e->src_rect.x + e->src_rect.w);
    193     }
    194 }
    195 
    196 /** setup mdp request */
    197 static void set_infos(struct copybit_context_t *dev, struct mdp_blit_req *req) {
    198     req->alpha = dev->mAlpha;
    199     req->transp_mask = MDP_TRANSP_NOP;
    200     req->flags = dev->mFlags | MDP_BLEND_FG_PREMULT;
    201 }
    202 
    203 /** copy the bits */
    204 static int msm_copybit(struct copybit_context_t *dev, void const *list)
    205 {
    206     int err = ioctl(dev->mFD, MSMFB_BLIT,
    207                     (struct mdp_blit_req_list const*)list);
    208     ALOGE_IF(err<0, "copyBits failed (%s)", strerror(errno));
    209     if (err == 0) {
    210         return 0;
    211     } else {
    212 #if DEBUG_MDP_ERRORS
    213         struct mdp_blit_req_list const* l = (struct mdp_blit_req_list const*)list;
    214         for (int i=0 ; i<l->count ; i++) {
    215             ALOGD("%d: src={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n"
    216                  "    dst={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n"
    217                  "    flags=%08lx"
    218                     ,
    219                     i,
    220                     l->req[i].src.width,
    221                     l->req[i].src.height,
    222                     l->req[i].src.format,
    223                     l->req[i].src_rect.x,
    224                     l->req[i].src_rect.y,
    225                     l->req[i].src_rect.w,
    226                     l->req[i].src_rect.h,
    227                     l->req[i].dst.width,
    228                     l->req[i].dst.height,
    229                     l->req[i].dst.format,
    230                     l->req[i].dst_rect.x,
    231                     l->req[i].dst_rect.y,
    232                     l->req[i].dst_rect.w,
    233                     l->req[i].dst_rect.h,
    234                     l->req[i].flags
    235             );
    236         }
    237 #endif
    238         return -errno;
    239     }
    240 }
    241 
    242 /*****************************************************************************/
    243 
    244 /** Set a parameter to value */
    245 static int set_parameter_copybit(
    246         struct copybit_device_t *dev,
    247         int name,
    248         int value)
    249 {
    250     struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
    251     int status = 0;
    252     if (ctx) {
    253         switch(name) {
    254         case COPYBIT_ROTATION_DEG:
    255             switch (value) {
    256             case 0:
    257                 ctx->mFlags &= ~0x7;
    258                 break;
    259             case 90:
    260                 ctx->mFlags &= ~0x7;
    261                 ctx->mFlags |= MDP_ROT_90;
    262                 break;
    263             case 180:
    264                 ctx->mFlags &= ~0x7;
    265                 ctx->mFlags |= MDP_ROT_180;
    266                 break;
    267             case 270:
    268                 ctx->mFlags &= ~0x7;
    269                 ctx->mFlags |= MDP_ROT_270;
    270                 break;
    271             default:
    272                 ALOGE("Invalid value for COPYBIT_ROTATION_DEG");
    273                 status = -EINVAL;
    274                 break;
    275             }
    276             break;
    277         case COPYBIT_PLANE_ALPHA:
    278             if (value < 0)      value = 0;
    279             if (value >= 256)   value = 255;
    280             ctx->mAlpha = value;
    281             break;
    282         case COPYBIT_DITHER:
    283             if (value == COPYBIT_ENABLE) {
    284                 ctx->mFlags |= MDP_DITHER;
    285             } else if (value == COPYBIT_DISABLE) {
    286                 ctx->mFlags &= ~MDP_DITHER;
    287             }
    288             break;
    289         case COPYBIT_BLUR:
    290             if (value == COPYBIT_ENABLE) {
    291                 ctx->mFlags |= MDP_BLUR;
    292             } else if (value == COPYBIT_DISABLE) {
    293                 ctx->mFlags &= ~MDP_BLUR;
    294             }
    295             break;
    296         case COPYBIT_TRANSFORM:
    297             ctx->mFlags &= ~0x7;
    298             ctx->mFlags |= value & 0x7;
    299             break;
    300         default:
    301             status = -EINVAL;
    302             break;
    303         }
    304     } else {
    305         status = -EINVAL;
    306     }
    307     return status;
    308 }
    309 
    310 /** Get a static info value */
    311 static int get(struct copybit_device_t *dev, int name)
    312 {
    313     struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
    314     int value;
    315     if (ctx) {
    316         switch(name) {
    317         case COPYBIT_MINIFICATION_LIMIT:
    318             value = MAX_SCALE_FACTOR;
    319             break;
    320         case COPYBIT_MAGNIFICATION_LIMIT:
    321             value = MAX_SCALE_FACTOR;
    322             break;
    323         case COPYBIT_SCALING_FRAC_BITS:
    324             value = 32;
    325             break;
    326         case COPYBIT_ROTATION_STEP_DEG:
    327             value = 90;
    328             break;
    329         default:
    330             value = -EINVAL;
    331         }
    332     } else {
    333         value = -EINVAL;
    334     }
    335     return value;
    336 }
    337 
    338 /** do a stretch blit type operation */
    339 static int stretch_copybit(
    340         struct copybit_device_t *dev,
    341         struct copybit_image_t const *dst,
    342         struct copybit_image_t const *src,
    343         struct copybit_rect_t const *dst_rect,
    344         struct copybit_rect_t const *src_rect,
    345         struct copybit_region_t const *region)
    346 {
    347     struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
    348     int status = 0;
    349     if (ctx) {
    350         struct {
    351             uint32_t count;
    352             struct mdp_blit_req req[12];
    353         } list;
    354 
    355         if (ctx->mAlpha < 255) {
    356             switch (src->format) {
    357                 // we don't support plane alpha with RGBA formats
    358                 case COPYBIT_FORMAT_RGBA_8888:
    359                 case COPYBIT_FORMAT_BGRA_8888:
    360                 case COPYBIT_FORMAT_RGBA_5551:
    361                 case COPYBIT_FORMAT_RGBA_4444:
    362                     return -EINVAL;
    363             }
    364         }
    365 
    366         if (src_rect->l < 0 || src_rect->r > src->w ||
    367             src_rect->t < 0 || src_rect->b > src->h) {
    368             // this is always invalid
    369             return -EINVAL;
    370         }
    371 
    372         if (src->w > MAX_DIMENSION || src->h > MAX_DIMENSION)
    373             return -EINVAL;
    374 
    375         if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION)
    376             return -EINVAL;
    377 
    378         const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]);
    379         const struct copybit_rect_t bounds = { 0, 0, dst->w, dst->h };
    380         struct copybit_rect_t clip;
    381         list.count = 0;
    382         status = 0;
    383         while ((status == 0) && region->next(region, &clip)) {
    384             intersect(&clip, &bounds, &clip);
    385             mdp_blit_req* req = &list.req[list.count];
    386             set_infos(ctx, req);
    387             set_image(&req->dst, dst);
    388             set_image(&req->src, src);
    389             set_rects(ctx, req, dst_rect, src_rect, &clip);
    390 
    391             if (req->src_rect.w<=0 || req->src_rect.h<=0)
    392                 continue;
    393 
    394             if (req->dst_rect.w<=0 || req->dst_rect.h<=0)
    395                 continue;
    396 
    397             if (++list.count == maxCount) {
    398                 status = msm_copybit(ctx, &list);
    399                 list.count = 0;
    400             }
    401         }
    402         if ((status == 0) && list.count) {
    403             status = msm_copybit(ctx, &list);
    404         }
    405     } else {
    406         status = -EINVAL;
    407     }
    408     return status;
    409 }
    410 
    411 /** Perform a blit type operation */
    412 static int blit_copybit(
    413         struct copybit_device_t *dev,
    414         struct copybit_image_t const *dst,
    415         struct copybit_image_t const *src,
    416         struct copybit_region_t const *region)
    417 {
    418     struct copybit_rect_t dr = { 0, 0, dst->w, dst->h };
    419     struct copybit_rect_t sr = { 0, 0, src->w, src->h };
    420     return stretch_copybit(dev, dst, src, &dr, &sr, region);
    421 }
    422 
    423 /*****************************************************************************/
    424 
    425 /** Close the copybit device */
    426 static int close_copybit(struct hw_device_t *dev)
    427 {
    428     struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
    429     if (ctx) {
    430         close(ctx->mFD);
    431         free(ctx);
    432     }
    433     return 0;
    434 }
    435 
    436 /** Open a new instance of a copybit device using name */
    437 static int open_copybit(const struct hw_module_t* module, const char* name,
    438         struct hw_device_t** device)
    439 {
    440     int status = -EINVAL;
    441     copybit_context_t *ctx;
    442     ctx = (copybit_context_t *)malloc(sizeof(copybit_context_t));
    443     memset(ctx, 0, sizeof(*ctx));
    444 
    445     ctx->device.common.tag = HARDWARE_DEVICE_TAG;
    446     ctx->device.common.version = 1;
    447     ctx->device.common.module = const_cast<hw_module_t*>(module);
    448     ctx->device.common.close = close_copybit;
    449     ctx->device.set_parameter = set_parameter_copybit;
    450     ctx->device.get = get;
    451     ctx->device.blit = blit_copybit;
    452     ctx->device.stretch = stretch_copybit;
    453     ctx->mAlpha = MDP_ALPHA_NOP;
    454     ctx->mFlags = 0;
    455     ctx->mFD = open("/dev/graphics/fb0", O_RDWR, 0);
    456 
    457     if (ctx->mFD < 0) {
    458         status = errno;
    459         ALOGE("Error opening frame buffer errno=%d (%s)",
    460              status, strerror(status));
    461         status = -status;
    462     } else {
    463         struct fb_fix_screeninfo finfo;
    464         if (ioctl(ctx->mFD, FBIOGET_FSCREENINFO, &finfo) == 0) {
    465             if (strcmp(finfo.id, "msmfb") == 0) {
    466                 /* Success */
    467                 status = 0;
    468             } else {
    469                 ALOGE("Error not msm frame buffer");
    470                 status = -EINVAL;
    471             }
    472         } else {
    473             ALOGE("Error executing ioctl for screen info");
    474             status = -errno;
    475         }
    476     }
    477 
    478     if (status == 0) {
    479         *device = &ctx->device.common;
    480     } else {
    481         close_copybit(&ctx->device.common);
    482     }
    483     return status;
    484 }
    485