Files
android_vendor_qcom_opensou…/libcopybit/copybit.cpp
Ramakant Singh 140965d6a4 hwc: Add dynamic fps support for PPP
Some apps like camera and video are running on
less fps than panel refresh rate. Hence setting
dynamic fps will help in reducing BW voting for PPP.

Change-Id: I236fe96d5c6547044083774388887638f9e32958
2015-03-05 19:38:06 -08:00

783 lines
25 KiB
C++

/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010 - 2014, 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 <cutils/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: &copybit_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);
}
/** 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_NV12_ENCODEABLE: return MDP_Y_CBCR_H2V2;
}
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 void 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);
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);
}
}
}
/** 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;
MetaData_t *metadata = NULL;
if (src_hnd != NULL)
metadata = (MetaData_t *)src_hnd->base_metadata;
if (metadata && (metadata->operation & UPDATE_COLOR_SPACE)) {
req->color_space = metadata->colorSpace;
}
set_infos(ctx, req, flags);
set_image(&req->dst, dst);
set_image(&req->src, src);
set_rects(ctx, req, dst_rect, src_rect, &clip);
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;
}