/* * Copyright (C) 2008 The Android Open Source Project * * 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. */ #define LOG_TAG "SurfaceFlinger" #include #include #include #include #include #include #include #include #include #if HAVE_ANDROID_OS #include #include #endif #include /******************************************************************************/ namespace android { class CopybitMSM7K : public copybit_t { public: CopybitMSM7K(); ~CopybitMSM7K(); status_t getStatus() const { if (mFD<0) return mFD; return NO_ERROR; } status_t setParameter(int name, int value); status_t get(int name); status_t blit( const copybit_image_t& dst, const copybit_image_t& src, copybit_region_t const* region); status_t stretch( const copybit_image_t& dst, const copybit_image_t& src, const copybit_rect_t& dst_rect, const copybit_rect_t& src_rect, copybit_region_t const* region); #if HAVE_ANDROID_OS private: static int copybit_set_parameter(copybit_t* handle, int name, int value); static int copybit_blit( copybit_t* handle, copybit_image_t const* dst, copybit_image_t const* src, copybit_region_t const* region); static int copybit_stretch(copybit_t* handle, copybit_image_t const* dst, copybit_image_t const* src, copybit_rect_t const* dst_rect, copybit_rect_t const* src_rect, copybit_region_t const* region); static int copybit_get(copybit_t* handle, int name); int getFormat(int format); void setImage(mdp_img* img, const copybit_image_t& rhs); void setRects(mdp_blit_req* req, const copybit_rect_t& dst, const copybit_rect_t& src, const copybit_rect_t& scissor); void setInfos(mdp_blit_req* req); static void intersect(copybit_rect_t* out, const copybit_rect_t& lhs, const copybit_rect_t& rhs); status_t msm_copybit(void const* list); #endif int mFD; uint8_t mAlpha; uint8_t mFlags; }; }; // namespace android using namespace android; /******************************************************************************/ struct copybit_t* copybit_init() { CopybitMSM7K* engine = new CopybitMSM7K(); if (engine->getStatus() != NO_ERROR) { delete engine; engine = 0; } return (struct copybit_t*)engine; } int copybit_term(copybit_t* handle) { delete static_cast(handle); return NO_ERROR; } namespace android { /******************************************************************************/ static inline int min(int a, int b) { return (ab) ? a : b; } 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; } } //----------------------------------------------------------------------------- #if HAVE_ANDROID_OS int CopybitMSM7K::copybit_set_parameter(copybit_t* handle, int name, int value) { return static_cast(handle)->setParameter(name, value); } int CopybitMSM7K::copybit_get(copybit_t* handle, int name) { return static_cast(handle)->get(name); } int CopybitMSM7K::copybit_blit( copybit_t* handle, copybit_image_t const* dst, copybit_image_t const* src, struct copybit_region_t const* region) { return static_cast(handle)->blit(*dst, *src, region); } int CopybitMSM7K::copybit_stretch( copybit_t* handle, copybit_image_t const* dst, copybit_image_t const* src, copybit_rect_t const* dst_rect, copybit_rect_t const* src_rect, struct copybit_region_t const* region) { return static_cast(handle)->stretch( *dst, *src, *dst_rect, *src_rect, region); } //----------------------------------------------------------------------------- CopybitMSM7K::CopybitMSM7K() : mFD(-1), mAlpha(MDP_ALPHA_NOP), mFlags(0) { int fd = open("/dev/graphics/fb0", O_RDWR, 0); if (fd > 0) { struct fb_fix_screeninfo finfo; if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == 0) { if (!strcmp(finfo.id, "msmfb")) { mFD = fd; copybit_t::set_parameter = copybit_set_parameter; copybit_t::get = copybit_get; copybit_t::blit = copybit_blit; copybit_t::stretch = copybit_stretch; } } } if (fd<0 || mFD<0) { if (fd>0) { close(fd); } mFD = -errno; } } CopybitMSM7K::~CopybitMSM7K() { if (mFD > 0){ close(mFD); } } status_t CopybitMSM7K::setParameter(int name, int value) { switch(name) { case COPYBIT_ROTATION_DEG: switch (value) { case 0: mFlags &= ~0x7; break; case 90: mFlags &= ~0x7; mFlags |= MDP_ROT_90; break; case 180: mFlags &= ~0x7; mFlags |= MDP_ROT_180; break; case 270: mFlags &= ~0x7; mFlags |= MDP_ROT_270; break; default: return BAD_VALUE; } break; case COPYBIT_PLANE_ALPHA: if (value < 0) value = 0; if (value >= 256) value = 255; mAlpha = value; break; case COPYBIT_DITHER: if (value == COPYBIT_ENABLE) { mFlags |= MDP_DITHER; } else if (value == COPYBIT_DISABLE) { mFlags &= ~MDP_DITHER; } break; case COPYBIT_TRANSFORM: mFlags &= ~0x7; mFlags |= value & 0x7; break; default: return BAD_VALUE; } return NO_ERROR; } status_t CopybitMSM7K::get(int name) { switch(name) { case COPYBIT_MINIFICATION_LIMIT: return 4; case COPYBIT_MAGNIFICATION_LIMIT: return 4; case COPYBIT_SCALING_FRAC_BITS: return 32; case COPYBIT_ROTATION_STEP_DEG: return 90; } return BAD_VALUE; } status_t CopybitMSM7K::blit( const copybit_image_t& dst, const copybit_image_t& src, copybit_region_t const* region) { copybit_rect_t dr = { 0, 0, dst.w, dst.h }; copybit_rect_t sr = { 0, 0, src.w, src.h }; return CopybitMSM7K::stretch(dst, src, dr, sr, region); } status_t CopybitMSM7K::stretch( const copybit_image_t& dst, const copybit_image_t& src, const copybit_rect_t& dst_rect, const copybit_rect_t& src_rect, copybit_region_t const* region) { struct { uint32_t count; struct mdp_blit_req req[12]; } list; if (mAlpha<255) { switch (src.format) { // we dont' support plane alpha with RGBA formats case COPYBIT_RGBA_8888: case COPYBIT_RGBA_5551: case COPYBIT_RGBA_4444: return INVALID_OPERATION; } } const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]); const copybit_rect_t bounds = { 0, 0, dst.w, dst.h }; copybit_rect_t clip; list.count = 0; int err = 0; while (!err && region->next(region, &clip)) { intersect(&clip, bounds, clip); setInfos(&list.req[list.count]); setImage(&list.req[list.count].dst, dst); setImage(&list.req[list.count].src, src); setRects(&list.req[list.count], dst_rect, src_rect, clip); if (++list.count == maxCount) { err = msm_copybit(&list); list.count = 0; } } if (!err && list.count) { err = msm_copybit(&list); } return err; } status_t CopybitMSM7K::msm_copybit(void const* list) { int err = ioctl(mFD, MSMFB_BLIT, static_cast(list)); LOGE_IF(err<0, "copyBits failed (%s)", strerror(errno)); if (err == 0) return NO_ERROR; return -errno; } int CopybitMSM7K::getFormat(int format) { switch (format) { case COPYBIT_RGBA_8888: return MDP_RGBA_8888; case COPYBIT_RGB_565: return MDP_RGB_565; case COPYBIT_YCbCr_422_SP: return MDP_Y_CBCR_H2V1; case COPYBIT_YCbCr_420_SP: return MDP_Y_CBCR_H2V2; } return -1; } void CopybitMSM7K::setInfos(mdp_blit_req* req) { req->alpha = mAlpha; req->transp_mask = MDP_TRANSP_NOP; req->flags = mFlags; } void CopybitMSM7K::setImage(mdp_img* img, const copybit_image_t& rhs) { img->width = rhs.w; img->height = rhs.h; img->format = getFormat(rhs.format); img->offset = rhs.offset; img->memory_id = rhs.fd; } void CopybitMSM7K::setRects(mdp_blit_req* e, const copybit_rect_t& dst, const copybit_rect_t& src, const copybit_rect_t& scissor) { 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; if (mFlags & COPYBIT_TRANSFORM_ROT_90) { e->src_rect.x = (clip.t - dst.t) + src.t; e->src_rect.y = (dst.r - clip.r) + src.l; 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 { e->src_rect.x = (clip.l - dst.l) + src.l; e->src_rect.y = (clip.t - dst.t) + src.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(e->src_rect.x, e->src_rect.w, src.r - src.l, W); MULDIV(e->src_rect.y, e->src_rect.h, src.b - src.t, H); if (mFlags & COPYBIT_TRANSFORM_FLIP_V) { e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h); } if (mFlags & COPYBIT_TRANSFORM_FLIP_H) { e->src_rect.x = e->src.width - (e->src_rect.x + e->src_rect.w); } } void CopybitMSM7K::intersect(copybit_rect_t* out, const copybit_rect_t& lhs, const 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); } /******************************************************************************/ #else // HAVE_ANDROID_OS CopybitMSM7K::CopybitMSM7K() : mFD(-1) { } CopybitMSM7K::~CopybitMSM7K() { } status_t CopybitMSM7K::setParameter(int name, int value) { return NO_INIT; } status_t CopybitMSM7K::get(int name) { return BAD_VALUE; } status_t CopybitMSM7K::blit( const copybit_image_t& dst, const copybit_image_t& src, copybit_region_t const* region) { return NO_INIT; } status_t CopybitMSM7K::stretch( const copybit_image_t& dst, const copybit_image_t& src, const copybit_rect_t& dst_rect, const copybit_rect_t& src_rect, copybit_region_t const* region) { return NO_INIT; } #endif // HAVE_ANDROID_OS /******************************************************************************/ }; // namespace android