copybit.cpp revision c9410082453abfb6eaaf43e6c97e04711d0751c0
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/******************************************************************************/
40
41#if defined(COPYBIT_MSM7K)
42#define MAX_SCALE_FACTOR    (4)
43#elif defined(COPYBIT_QSD8K)
44#define MAX_SCALE_FACTOR    (8)
45#else
46#error "Unsupported MDP version"
47#endif
48
49/******************************************************************************/
50
51/** State information for each device instance */
52struct copybit_context_t {
53    struct copybit_device_t device;
54    int     mFD;
55    uint8_t mAlpha;
56    uint8_t mFlags;
57};
58
59/**
60 * Common hardware methods
61 */
62
63static int open_copybit(const struct hw_module_t* module, const char* name,
64        struct hw_device_t** device);
65
66static struct hw_module_methods_t copybit_module_methods = {
67    open:  open_copybit
68};
69
70/*
71 * The COPYBIT Module
72 */
73struct copybit_module_t HAL_MODULE_INFO_SYM = {
74    common: {
75        tag: HARDWARE_MODULE_TAG,
76        version_major: 1,
77        version_minor: 0,
78        id: COPYBIT_HARDWARE_MODULE_ID,
79        name: "QCT MSM7K COPYBIT Module",
80        author: "Google, Inc.",
81        methods: &copybit_module_methods
82    }
83};
84
85/******************************************************************************/
86
87/** min of int a, b */
88static inline int min(int a, int b) {
89    return (a<b) ? a : b;
90}
91
92/** max of int a, b */
93static inline int max(int a, int b) {
94    return (a>b) ? a : b;
95}
96
97/** scale each parameter by mul/div. Assume div isn't 0 */
98static inline void MULDIV(uint32_t *a, uint32_t *b, int mul, int div) {
99    if (mul != div) {
100        *a = (mul * *a) / div;
101        *b = (mul * *b) / div;
102    }
103}
104
105/** Determine the intersection of lhs & rhs store in out */
106static void intersect(struct copybit_rect_t *out,
107                      const struct copybit_rect_t *lhs,
108                      const struct copybit_rect_t *rhs) {
109    out->l = max(lhs->l, rhs->l);
110    out->t = max(lhs->t, rhs->t);
111    out->r = min(lhs->r, rhs->r);
112    out->b = min(lhs->b, rhs->b);
113}
114
115/** convert COPYBIT_FORMAT to MDP format */
116static int get_format(int format) {
117    switch (format) {
118    case COPYBIT_FORMAT_RGB_565:       return MDP_RGB_565;
119    case COPYBIT_FORMAT_RGBX_8888:     return MDP_RGBX_8888;
120    case COPYBIT_FORMAT_RGB_888:       return MDP_RGB_888;
121    case COPYBIT_FORMAT_RGBA_8888:     return MDP_RGBA_8888;
122    case COPYBIT_FORMAT_BGRA_8888:     return MDP_BGRA_8888;
123    case COPYBIT_FORMAT_YCbCr_422_SP:  return MDP_Y_CBCR_H2V1;
124    case COPYBIT_FORMAT_YCbCr_420_SP:  return MDP_Y_CBCR_H2V2;
125    }
126    return -1;
127}
128
129/** convert from copybit image to mdp image structure */
130static void set_image(struct mdp_img *img, const struct copybit_image_t *rhs)
131{
132    private_handle_t* hnd = (private_handle_t*)rhs->handle;
133    img->width      = rhs->w;
134    img->height     = rhs->h;
135    img->format     = get_format(rhs->format);
136    img->offset     = hnd->offset;
137#if defined(COPYBIT_MSM7K)
138    if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_GPU) {
139        img->memory_id = hnd->gpu_fd;
140        if (img->format == MDP_RGBA_8888) {
141            // msm7201A GPU only supports BGRA_8888 destinations
142            img->format = MDP_BGRA_8888;
143        }
144    } else {
145        img->memory_id = hnd->fd;
146    }
147#else
148    img->memory_id  = hnd->fd;
149#endif
150}
151/** setup rectangles */
152static void set_rects(struct copybit_context_t *dev,
153                      struct mdp_blit_req *e,
154                      const struct copybit_rect_t *dst,
155                      const struct copybit_rect_t *src,
156                      const struct copybit_rect_t *scissor) {
157    struct copybit_rect_t clip;
158    intersect(&clip, scissor, dst);
159
160    e->dst_rect.x  = clip.l;
161    e->dst_rect.y  = clip.t;
162    e->dst_rect.w  = clip.r - clip.l;
163    e->dst_rect.h  = clip.b - clip.t;
164
165    uint32_t W, H;
166    if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) {
167        e->src_rect.x = (clip.t - dst->t) + src->t;
168        e->src_rect.y = (dst->r - clip.r) + src->l;
169        e->src_rect.w = (clip.b - clip.t);
170        e->src_rect.h = (clip.r - clip.l);
171        W = dst->b - dst->t;
172        H = dst->r - dst->l;
173    } else {
174        e->src_rect.x  = (clip.l - dst->l) + src->l;
175        e->src_rect.y  = (clip.t - dst->t) + src->t;
176        e->src_rect.w  = (clip.r - clip.l);
177        e->src_rect.h  = (clip.b - clip.t);
178        W = dst->r - dst->l;
179        H = dst->b - dst->t;
180    }
181    MULDIV(&e->src_rect.x, &e->src_rect.w, src->r - src->l, W);
182    MULDIV(&e->src_rect.y, &e->src_rect.h, src->b - src->t, H);
183    if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_V) {
184        e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h);
185    }
186    if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_H) {
187        e->src_rect.x = e->src.width  - (e->src_rect.x + e->src_rect.w);
188    }
189}
190
191/** setup mdp request */
192static void set_infos(struct copybit_context_t *dev, struct mdp_blit_req *req) {
193    req->alpha = dev->mAlpha;
194    req->transp_mask = MDP_TRANSP_NOP;
195    req->flags = dev->mFlags;
196}
197
198/** copy the bits */
199static int msm_copybit(struct copybit_context_t *dev, void const *list)
200{
201    int err = ioctl(dev->mFD, MSMFB_BLIT,
202                    (struct mdp_blit_req_list const*)list);
203    LOGE_IF(err<0, "copyBits failed (%s)", strerror(errno));
204    if (err == 0)
205        return 0;
206    else
207        return -errno;
208}
209
210/*****************************************************************************/
211
212/** Set a parameter to value */
213static int set_parameter_copybit(
214        struct copybit_device_t *dev,
215        int name,
216        int value)
217{
218    struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
219    int status = 0;
220    if (ctx) {
221        switch(name) {
222        case COPYBIT_ROTATION_DEG:
223            switch (value) {
224            case 0:
225                ctx->mFlags &= ~0x7;
226                break;
227            case 90:
228                ctx->mFlags &= ~0x7;
229                ctx->mFlags |= MDP_ROT_90;
230                break;
231            case 180:
232                ctx->mFlags &= ~0x7;
233                ctx->mFlags |= MDP_ROT_180;
234                break;
235            case 270:
236                ctx->mFlags &= ~0x7;
237                ctx->mFlags |= MDP_ROT_270;
238                break;
239            default:
240                LOGE("Invalid value for COPYBIT_ROTATION_DEG");
241                status = -EINVAL;
242                break;
243            }
244            break;
245        case COPYBIT_PLANE_ALPHA:
246            if (value < 0)      value = 0;
247            if (value >= 256)   value = 255;
248            ctx->mAlpha = value;
249            break;
250        case COPYBIT_DITHER:
251            if (value == COPYBIT_ENABLE) {
252                ctx->mFlags |= MDP_DITHER;
253            } else if (value == COPYBIT_DISABLE) {
254                ctx->mFlags &= ~MDP_DITHER;
255            }
256            break;
257        case COPYBIT_BLUR:
258            if (value == COPYBIT_ENABLE) {
259                ctx->mFlags |= MDP_BLUR;
260            } else if (value == COPYBIT_DISABLE) {
261                ctx->mFlags &= ~MDP_BLUR;
262            }
263            break;
264        case COPYBIT_TRANSFORM:
265            ctx->mFlags &= ~0x7;
266            ctx->mFlags |= value & 0x7;
267            break;
268        default:
269            status = -EINVAL;
270            break;
271        }
272    } else {
273        status = -EINVAL;
274    }
275    return status;
276}
277
278/** Get a static info value */
279static int get(struct copybit_device_t *dev, int name)
280{
281    struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
282    int value;
283    if (ctx) {
284        switch(name) {
285        case COPYBIT_MINIFICATION_LIMIT:
286            value = MAX_SCALE_FACTOR;
287            break;
288        case COPYBIT_MAGNIFICATION_LIMIT:
289            value = MAX_SCALE_FACTOR;
290            break;
291        case COPYBIT_SCALING_FRAC_BITS:
292            value = 32;
293            break;
294        case COPYBIT_ROTATION_STEP_DEG:
295            value = 90;
296            break;
297        default:
298            value = -EINVAL;
299        }
300    } else {
301        value = -EINVAL;
302    }
303    return value;
304}
305
306/** do a stretch blit type operation */
307static int stretch_copybit(
308        struct copybit_device_t *dev,
309        struct copybit_image_t const *dst,
310        struct copybit_image_t const *src,
311        struct copybit_rect_t const *dst_rect,
312        struct copybit_rect_t const *src_rect,
313        struct copybit_region_t const *region)
314{
315    struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
316    int status = 0;
317    if (ctx) {
318        struct {
319            uint32_t count;
320            struct mdp_blit_req req[12];
321        } list;
322
323        if (ctx->mAlpha < 255) {
324            switch (src->format) {
325                // we don't support plane alpha with RGBA formats
326                case COPYBIT_FORMAT_RGBA_8888:
327                case COPYBIT_FORMAT_BGRA_8888:
328                case COPYBIT_FORMAT_RGBA_5551:
329                case COPYBIT_FORMAT_RGBA_4444:
330                    return -EINVAL;
331            }
332        }
333
334        const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]);
335        const struct copybit_rect_t bounds = { 0, 0, dst->w, dst->h };
336        struct copybit_rect_t clip;
337        list.count = 0;
338        status = 0;
339        while ((status == 0) && region->next(region, &clip)) {
340            intersect(&clip, &bounds, &clip);
341            set_infos(ctx, &list.req[list.count]);
342            set_image(&list.req[list.count].dst, dst);
343            set_image(&list.req[list.count].src, src);
344            set_rects(ctx, &list.req[list.count], dst_rect, src_rect, &clip);
345            if (++list.count == maxCount) {
346                status = msm_copybit(ctx, &list);
347                list.count = 0;
348            }
349        }
350        if ((status == 0) && list.count) {
351            status = msm_copybit(ctx, &list);
352        }
353    } else {
354        status = -EINVAL;
355    }
356    return status;
357}
358
359/** Perform a blit type operation */
360static int blit_copybit(
361        struct copybit_device_t *dev,
362        struct copybit_image_t const *dst,
363        struct copybit_image_t const *src,
364        struct copybit_region_t const *region)
365{
366    struct copybit_rect_t dr = { 0, 0, dst->w, dst->h };
367    struct copybit_rect_t sr = { 0, 0, src->w, src->h };
368    return stretch_copybit(dev, dst, src, &dr, &sr, region);
369}
370
371/*****************************************************************************/
372
373/** Close the copybit device */
374static int close_copybit(struct hw_device_t *dev)
375{
376    struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
377    if (ctx) {
378        close(ctx->mFD);
379        free(ctx);
380    }
381    return 0;
382}
383
384/** Open a new instance of a copybit device using name */
385static int open_copybit(const struct hw_module_t* module, const char* name,
386        struct hw_device_t** device)
387{
388    int status = -EINVAL;
389    copybit_context_t *ctx;
390    ctx = (copybit_context_t *)malloc(sizeof(copybit_context_t));
391    memset(ctx, 0, sizeof(*ctx));
392
393    ctx->device.common.tag = HARDWARE_DEVICE_TAG;
394    ctx->device.common.version = 1;
395    ctx->device.common.module = const_cast<hw_module_t*>(module);
396    ctx->device.common.close = close_copybit;
397    ctx->device.set_parameter = set_parameter_copybit;
398    ctx->device.get = get;
399    ctx->device.blit = blit_copybit;
400    ctx->device.stretch = stretch_copybit;
401    ctx->mAlpha = MDP_ALPHA_NOP;
402    ctx->mFlags = 0;
403    ctx->mFD = open("/dev/graphics/fb0", O_RDWR, 0);
404
405    if (ctx->mFD < 0) {
406        status = errno;
407        LOGE("Error opening frame buffer errno=%d (%s)",
408             status, strerror(status));
409        status = -status;
410    } else {
411        struct fb_fix_screeninfo finfo;
412        if (ioctl(ctx->mFD, FBIOGET_FSCREENINFO, &finfo) == 0) {
413            if (strcmp(finfo.id, "msmfb") == 0) {
414                /* Success */
415                status = 0;
416            } else {
417                LOGE("Error not msm frame buffer");
418                status = -EINVAL;
419            }
420        } else {
421            LOGE("Error executing ioctl for screen info");
422            status = -errno;
423        }
424    }
425
426    if (status == 0) {
427        *device = &ctx->device.common;
428    } else {
429        close_copybit(&ctx->device.common);
430    }
431    return status;
432}
433