diff --git a/common.mk b/common.mk index 3c34f7c..0bc64a3 100644 --- a/common.mk +++ b/common.mk @@ -2,6 +2,7 @@ common_includes := hardware/qcom/display/libgralloc common_includes += hardware/qcom/display/libgenlock common_includes += hardware/qcom/display/liboverlay +common_includes += hardware/qcom/display/libcopybit common_includes += hardware/qcom/display/libqdutils ifeq ($(TARGET_USES_POST_PROCESSING),true) diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp index 886d12b..ee8c12e 100644 --- a/libcopybit/copybit.cpp +++ b/libcopybit/copybit.cpp @@ -60,6 +60,7 @@ struct copybit_context_t { int mFD; uint8_t mAlpha; int mFlags; + bool mBlitToFB; }; /** @@ -212,6 +213,10 @@ static void set_infos(struct copybit_context_t *dev, req->alpha = dev->mAlpha; 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 @@ -229,10 +234,10 @@ static int msm_copybit(struct copybit_context_t *dev, void const *list) #if DEBUG_MDP_ERRORS struct mdp_blit_req_list const* l = (struct mdp_blit_req_list const*)list; - for (int i=0 ; icount ; i++) { + for (unsigned int i=0 ; icount ; 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=%08lx" + " flags=%08x" , i, l->req[i].src.width, @@ -322,6 +327,16 @@ static int set_parameter_copybit( 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; default: status = -EINVAL; break; @@ -391,8 +406,8 @@ static int stretch_copybit( } } - if (src_rect->l < 0 || src_rect->r > src->w || - src_rect->t < 0 || src_rect->b > src->h) { + 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); diff --git a/libcopybit/copybit.h b/libcopybit/copybit.h index 6384dfe..c14af74 100644 --- a/libcopybit/copybit.h +++ b/libcopybit/copybit.h @@ -52,6 +52,10 @@ enum { /* name for copybit_set_parameter */ enum { + /* Default blit destination is offline buffer */ + /* clients to set this to '1', if blitting to framebuffer */ + /* and reset to '0', after calling blit/stretch */ + COPYBIT_BLIT_TO_FRAMEBUFFER = 0, /* rotation of the source image in degrees (0 to 359) */ COPYBIT_ROTATION_DEG = 1, /* plane alpha value */ diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk index 8e04606..5067a2a 100644 --- a/libhwcomposer/Android.mk +++ b/libhwcomposer/Android.mk @@ -6,9 +6,10 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) LOCAL_SHARED_LIBRARIES := $(common_libs) libEGL liboverlay libgenlock \ - libqdutils libhardware_legacy + libqdutils libhardware_legacy libdl libmemalloc LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"hwcomposer\" LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) LOCAL_SRC_FILES := hwc.cpp hwc_video.cpp hwc_utils.cpp \ - hwc_uimirror.cpp hwc_ext_observer.cpp + hwc_uimirror.cpp hwc_ext_observer.cpp \ + hwc_copybit.cpp include $(BUILD_SHARED_LIBRARY) diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp index 8aa6e83..34972b7 100644 --- a/libhwcomposer/hwc.cpp +++ b/libhwcomposer/hwc.cpp @@ -20,11 +20,11 @@ #include #include -#include #include "hwc_utils.h" #include "hwc_video.h" #include "hwc_uimirror.h" +#include "hwc_copybit.h" using namespace qhwc; @@ -82,7 +82,11 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) } else if (0) { //Other features ctx->overlayInUse = true; + } else { // Else set this flag to false, otherwise video cases + // fail in non-overlay targets. + ctx->overlayInUse = false; } + CopyBit::prepare(ctx, list); } return 0; @@ -97,6 +101,7 @@ static int hwc_set(hwc_composer_device_t *dev, hwc_context_t* ctx = (hwc_context_t*)(dev); if (LIKELY(list)) { VideoOverlay::draw(ctx, list); + CopyBit::draw(ctx, list, (EGLDisplay)dpy, (EGLSurface)sur); EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); UIMirrorOverlay::draw(ctx); } else { diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp new file mode 100644 index 0000000..adcd4dc --- /dev/null +++ b/libhwcomposer/hwc_copybit.cpp @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. 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 "hwc_copybit.h" +#include "hwc_copybitEngine.h" + +namespace qhwc { + + +struct range { + int current; + int end; +}; +struct region_iterator : public copybit_region_t { + + region_iterator(hwc_region_t region) { + mRegion = region; + r.end = region.numRects; + r.current = 0; + this->next = iterate; + } + +private: + static int iterate(copybit_region_t const * self, copybit_rect_t* rect){ + if (!self || !rect) { + ALOGE("iterate invalid parameters"); + return 0; + } + + region_iterator const* me = + static_cast(self); + if (me->r.current != me->r.end) { + rect->l = me->mRegion.rects[me->r.current].left; + rect->t = me->mRegion.rects[me->r.current].top; + rect->r = me->mRegion.rects[me->r.current].right; + rect->b = me->mRegion.rects[me->r.current].bottom; + me->r.current++; + return 1; + } + return 0; + } + + hwc_region_t mRegion; + mutable range r; +}; + +// Initialize CopyBit Class Static Mmembers. +functype_eglGetRenderBufferANDROID CopyBit::LINK_eglGetRenderBufferANDROID + = NULL; +functype_eglGetCurrentSurface CopyBit::LINK_eglGetCurrentSurface = NULL; +int CopyBit::sYuvCount = 0; +int CopyBit::sYuvLayerIndex = -1; +bool CopyBit::sIsModeOn = false; +bool CopyBit::sIsLayerSkip = false; +void* CopyBit::egl_lib = NULL; + +void CopyBit::updateEglHandles(void* egl_lib) +{ + if(egl_lib != NULL) { + *(void **)&CopyBit::LINK_eglGetRenderBufferANDROID = + ::dlsym(egl_lib, "eglGetRenderBufferANDROID"); + *(void **)&CopyBit::LINK_eglGetCurrentSurface = + ::dlsym(egl_lib, "eglGetCurrentSurface"); + }else { + LINK_eglGetCurrentSurface = NULL; + LINK_eglGetCurrentSurface = NULL; + } +} + +bool CopyBit::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { + for (int i=list->numHwLayers-1; i >= 0 ; i--) { + private_handle_t *hnd = + (private_handle_t *)list->hwLayers[i].handle; + if (isSkipLayer(&list->hwLayers[i])) { + break; + } else if(canUseCopybit(ctx, list, getYuvCount()) + && !ctx->overlayInUse){ + list->hwLayers[i].compositionType = HWC_USE_COPYBIT; + } else { + list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + } + } + return true; +} +bool CopyBit::draw(hwc_context_t *ctx, hwc_layer_list_t *list, EGLDisplay dpy, + EGLSurface sur){ + for (size_t i=0; inumHwLayers; i++) { + if (list->hwLayers[i].flags & HWC_SKIP_LAYER) { + continue; + } else if (list->hwLayers[i].compositionType == HWC_USE_COPYBIT) { + drawLayerUsingCopybit(ctx, &(list->hwLayers[i]), + (EGLDisplay)dpy, + (EGLSurface)sur, + LINK_eglGetRenderBufferANDROID, + LINK_eglGetCurrentSurface); + } + } + return true; +} + +int CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_t *layer, + EGLDisplay dpy, + EGLSurface surface, + functype_eglGetRenderBufferANDROID& LINK_eglGetRenderBufferANDROID, + functype_eglGetCurrentSurface LINK_eglGetCurrentSurface) +{ + hwc_context_t* ctx = (hwc_context_t*)(dev); + if(!ctx) { + ALOGE("%s: null context ", __FUNCTION__); + return -1; + } + + private_handle_t *hnd = (private_handle_t *)layer->handle; + if(!hnd) { + ALOGE("%s: invalid handle", __FUNCTION__); + return -1; + } + + // Lock this buffer for read. + genlock_lock_type lockType = GENLOCK_READ_LOCK; + int err = genlock_lock_buffer(hnd, lockType, GENLOCK_MAX_TIMEOUT); + if (GENLOCK_FAILURE == err) { + ALOGE("%s: genlock_lock_buffer(READ) failed", __FUNCTION__); + return -1; + } + //render buffer + EGLSurface eglSurface = LINK_eglGetCurrentSurface(EGL_DRAW); + android_native_buffer_t *renderBuffer = + (android_native_buffer_t *)LINK_eglGetRenderBufferANDROID(dpy, eglSurface); + if (!renderBuffer) { + ALOGE("%s: eglGetRenderBuffer returned NULL buffer", __FUNCTION__); + genlock_unlock_buffer(hnd); + return -1; + } + private_handle_t *fbHandle = (private_handle_t *)renderBuffer->handle; + if(!fbHandle) { + ALOGE("%s: Framebuffer handle is NULL", __FUNCTION__); + genlock_unlock_buffer(hnd); + return -1; + } + + // Set the copybit source: + copybit_image_t src; + src.w = hnd->width; + src.h = hnd->height; + src.format = hnd->format; + src.base = (void *)hnd->base; + src.handle = (native_handle_t *)layer->handle; + src.horiz_padding = src.w - hnd->width; + // Initialize vertical padding to zero for now, + // this needs to change to accomodate vertical stride + // if needed in the future + src.vert_padding = 0; + // Remove the srcBufferTransform if any + layer->transform = (layer->transform & FINAL_TRANSFORM_MASK); + + // Copybit source rect + hwc_rect_t sourceCrop = layer->sourceCrop; + copybit_rect_t srcRect = {sourceCrop.left, sourceCrop.top, + sourceCrop.right, + sourceCrop.bottom}; + + // Copybit destination rect + hwc_rect_t displayFrame = layer->displayFrame; + copybit_rect_t dstRect = {displayFrame.left, displayFrame.top, + displayFrame.right, + displayFrame.bottom}; + + // Copybit dst + copybit_image_t dst; + dst.w = ALIGN(fbHandle->width,32); + dst.h = fbHandle->height; + dst.format = fbHandle->format; + dst.base = (void *)fbHandle->base; + dst.handle = (native_handle_t *)renderBuffer->handle; + + copybit_device_t *copybit = ctx->mCopybitEngine->getEngine(); + + int32_t screen_w = displayFrame.right - displayFrame.left; + int32_t screen_h = displayFrame.bottom - displayFrame.top; + int32_t src_crop_width = sourceCrop.right - sourceCrop.left; + int32_t src_crop_height = sourceCrop.bottom -sourceCrop.top; + + // Copybit dst + float copybitsMaxScale = + (float)copybit->get(copybit,COPYBIT_MAGNIFICATION_LIMIT); + float copybitsMinScale = + (float)copybit->get(copybit,COPYBIT_MINIFICATION_LIMIT); + + if((layer->transform == HWC_TRANSFORM_ROT_90) || + (layer->transform == HWC_TRANSFORM_ROT_270)) { + //swap screen width and height + int tmp = screen_w; + screen_w = screen_h; + screen_h = tmp; + } + private_handle_t *tmpHnd = NULL; + + if(screen_w <=0 || screen_h<=0 ||src_crop_width<=0 || src_crop_height<=0 ) { + ALOGE("%s: wrong params for display screen_w=%d src_crop_width=%d \ + screen_w=%d src_crop_width=%d", __FUNCTION__, screen_w, + src_crop_width,screen_w,src_crop_width); + genlock_unlock_buffer(hnd); + return -1; + } + + float dsdx = (float)screen_w/src_crop_width; + float dtdy = (float)screen_h/src_crop_height; + + float scaleLimitMax = copybitsMaxScale * copybitsMaxScale; + float scaleLimitMin = copybitsMinScale * copybitsMinScale; + if(dsdx > scaleLimitMax || + dtdy > scaleLimitMax || + dsdx < 1/scaleLimitMin || + dtdy < 1/scaleLimitMin) { + ALOGE("%s: greater than max supported size dsdx=%f dtdy=%f \ + scaleLimitMax=%f scaleLimitMin=%f", __FUNCTION__,dsdx,dtdy, + scaleLimitMax,1/scaleLimitMin); + genlock_unlock_buffer(hnd); + return -1; + } + if(dsdx > copybitsMaxScale || + dtdy > copybitsMaxScale || + dsdx < 1/copybitsMinScale || + dtdy < 1/copybitsMinScale){ + // The requested scale is out of the range the hardware + // can support. + ALOGE("%s:%d::Need to scale twice dsdx=%f, dtdy=%f,copybitsMaxScale=%f,\ + copybitsMinScale=%f,screen_w=%d,screen_h=%d \ + src_crop_width=%d src_crop_height=%d",__FUNCTION__,__LINE__, + dsdx,dtdy,copybitsMaxScale,1/copybitsMinScale,screen_w,screen_h, + src_crop_width,src_crop_height); + + //Driver makes width and height as even + //that may cause wrong calculation of the ratio + //in display and crop.Hence we make + //crop width and height as even. + src_crop_width = (src_crop_width/2)*2; + src_crop_height = (src_crop_height/2)*2; + + int tmp_w = src_crop_width; + int tmp_h = src_crop_height; + + if (dsdx > copybitsMaxScale || dtdy > copybitsMaxScale ){ + tmp_w = src_crop_width*copybitsMaxScale; + tmp_h = src_crop_height*copybitsMaxScale; + }else if (dsdx < 1/copybitsMinScale ||dtdy < 1/copybitsMinScale ){ + tmp_w = src_crop_width/copybitsMinScale; + tmp_h = src_crop_height/copybitsMinScale; + tmp_w = (tmp_w/2)*2; + tmp_h = (tmp_h/2)*2; + } + ALOGE("%s:%d::tmp_w = %d,tmp_h = %d",__FUNCTION__,__LINE__,tmp_w,tmp_h); + + int usage = GRALLOC_USAGE_PRIVATE_MM_HEAP; + + if (0 == alloc_buffer(&tmpHnd, tmp_w, tmp_h, fbHandle->format, usage)){ + copybit_image_t tmp_dst; + copybit_rect_t tmp_rect; + tmp_dst.w = tmp_w; + tmp_dst.h = tmp_h; + tmp_dst.format = tmpHnd->format; + tmp_dst.handle = tmpHnd; + tmp_dst.horiz_padding = src.horiz_padding; + tmp_dst.vert_padding = src.vert_padding; + tmp_rect.l = 0; + tmp_rect.t = 0; + tmp_rect.r = tmp_dst.w; + tmp_rect.b = tmp_dst.h; + //create one clip region + hwc_rect tmp_hwc_rect = {0,0,tmp_rect.r,tmp_rect.b}; + hwc_region_t tmp_hwc_reg = {1,(hwc_rect_t const*)&tmp_hwc_rect}; + region_iterator tmp_it(tmp_hwc_reg); + copybit->set_parameter(copybit,COPYBIT_TRANSFORM,0); + // TODO : alpha not defined , fix this + // copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, + // (layer->blending == HWC_BLENDING_NONE) ? -1 : layer->alpha); + err = copybit->stretch(copybit,&tmp_dst, &src, &tmp_rect, + &srcRect, &tmp_it); + if(err < 0){ + ALOGE("%s:%d::tmp copybit stretch failed",__FUNCTION__, + __LINE__); + if(tmpHnd) + free_buffer(tmpHnd); + genlock_unlock_buffer(hnd); + return err; + } + // copy new src and src rect crop + src = tmp_dst; + srcRect = tmp_rect; + } + } + // Copybit region + hwc_region_t region = layer->visibleRegionScreen; + region_iterator copybitRegion(region); + + copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH, + renderBuffer->width); + copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT, + renderBuffer->height); + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, + layer->transform); + // TODO : alpha not defined , fix this + // copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, + // (layer->blending == HWC_BLENDING_NONE) ? -1 : layer->alpha); + copybit->set_parameter(copybit, COPYBIT_PREMULTIPLIED_ALPHA, + (layer->blending == HWC_BLENDING_PREMULT)? + COPYBIT_ENABLE : COPYBIT_DISABLE); + copybit->set_parameter(copybit, COPYBIT_DITHER, + (dst.format == HAL_PIXEL_FORMAT_RGB_565)? + COPYBIT_ENABLE : COPYBIT_DISABLE); + copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER, + COPYBIT_ENABLE); + err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect, + ©bitRegion); + copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER, + COPYBIT_DISABLE); + + if(tmpHnd) + free_buffer(tmpHnd); + + if(err < 0) + ALOGE("%s: copybit stretch failed",__FUNCTION__); + + // Unlock this buffer since copybit is done with it. + err = genlock_unlock_buffer(hnd); + if (GENLOCK_FAILURE == err) { + ALOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); + } + + return err; +} + +void CopyBit::getLayerResolution(const hwc_layer_t* layer, int& width, + int& height) +{ + hwc_rect_t displayFrame = layer->displayFrame; + + width = displayFrame.right - displayFrame.left; + height = displayFrame.bottom - displayFrame.top; +} + +bool CopyBit::canUseCopybit(hwc_context_t *ctx, const hwc_layer_list_t* list, + const int numYUVBuffers) +{ + // XXX : TODO , currently returning false for MDP4 targets, + // This has to be modified after adding C2D support. + if(ctx->hasOverlay) + return false; + + framebuffer_device_t* fbDev = ctx->mFbDevice->getFb(); + if(!fbDev) { + ALOGE("ERROR: canUseCopybit : fb device is invalid"); + return false; + } + + if (!list) + return false; + + // If , couldnt link to adreno library return false. + if(LINK_eglGetRenderBufferANDROID == NULL || + LINK_eglGetCurrentSurface == NULL ) + return false; + + if(!ctx->hasOverlay) { + if (numYUVBuffers) + return true; + } + + int fb_w = fbDev->width; + int fb_h = fbDev->height; + + /* + * Use copybit only when we need to blit + * max 2 full screen sized regions + */ + + unsigned int renderArea = 0; + + for(unsigned int i = 0; i < list->numHwLayers; i++ ) { + int w, h; + getLayerResolution(&list->hwLayers[i], w, h); + renderArea += w*h; + } + + return (renderArea <= (2 * fb_w * fb_h)); +} +void CopyBit::openEglLibAndGethandle() +{ + egl_lib = ::dlopen("libEGL_adreno200.so", RTLD_GLOBAL | RTLD_LAZY); + if (!egl_lib) { + return; + } + updateEglHandles(egl_lib); +} +void CopyBit::closeEglLib() +{ + if(egl_lib) + ::dlclose(egl_lib); + + egl_lib = NULL; + updateEglHandles(NULL); +} + + + +//CopybitEngine Class functions +CopybitEngine* CopybitEngine::sInstance = 0;; + +struct copybit_device_t* CopybitEngine::getEngine() { + return sEngine; +} +CopybitEngine* CopybitEngine::getInstance() { + if(sInstance == NULL) + sInstance = new CopybitEngine(); + return sInstance; +} + +CopybitEngine::CopybitEngine(){ + hw_module_t const *module; + if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) { + copybit_open(module, &sEngine); + } else { + ALOGE("FATAL ERROR: copybit open failed."); + } +} +CopybitEngine::~CopybitEngine() +{ + if(sEngine) + { + copybit_close(sEngine); + sEngine = NULL; + } +} + +}; //namespace qhwc diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h new file mode 100644 index 0000000..adf088b --- /dev/null +++ b/libhwcomposer/hwc_copybit.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. 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. + */ +#ifndef HWC_COPYBIT_H +#define HWC_COPYBIT_H +#include "hwc_utils.h" +#include +#include +#include +#include +#include + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +namespace qhwc { +//Feature for using Copybit to display RGB layers. +class CopyBit { +public: + //Sets up members and prepares copybit if conditions are met + static bool prepare(hwc_context_t *ctx, hwc_layer_list_t *list); + //Draws layer if the layer is set for copybit in prepare + static bool draw(hwc_context_t *ctx, hwc_layer_list_t *list, EGLDisplay dpy, + EGLSurface sur); + //Receives data from hwc + static void setStats(int yuvCount, int yuvLayerIndex, bool isYuvLayerSkip); + + static void updateEglHandles(void*); + static int drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_t *layer, + EGLDisplay dpy, EGLSurface surface, + functype_eglGetRenderBufferANDROID& LINK_eglGetRenderBufferANDROID, + functype_eglGetCurrentSurface LINK_eglGetCurrentSurface); + static bool canUseCopybit(hwc_context_t* ctx, const hwc_layer_list_t* list, + const int numYUVBuffers); + static void closeEglLib(); + static void openEglLibAndGethandle(); +private: + //Marks layer flags if this feature is used + static void markFlags(hwc_layer_t *layer); + //returns yuv count + static int getYuvCount(); + + //Number of yuv layers in this drawing round + static int sYuvCount; + //Index of YUV layer, relevant only if count is 1 + static int sYuvLayerIndex; + //Flags if a yuv layer is animating or below something that is animating + static bool sIsLayerSkip; + //Flags if this feature is on. + static bool sIsModeOn; + //handle for adreno lib + static void* egl_lib; + + static functype_eglGetRenderBufferANDROID LINK_eglGetRenderBufferANDROID; + static functype_eglGetCurrentSurface LINK_eglGetCurrentSurface; + + static void getLayerResolution(const hwc_layer_t* layer, int& width, + int& height); + +}; + +inline void CopyBit::setStats(int yuvCount, int yuvLayerIndex, + bool isYuvLayerSkip) { + sYuvCount = yuvCount; + sYuvLayerIndex = yuvLayerIndex; + sIsLayerSkip = isYuvLayerSkip; +} + +inline int CopyBit::getYuvCount() { return sYuvCount; } + + +}; //namespace qhwc + +#endif //HWC_COPYBIT_H diff --git a/libhwcomposer/hwc_copybitEngine.h b/libhwcomposer/hwc_copybitEngine.h new file mode 100644 index 0000000..d627e44 --- /dev/null +++ b/libhwcomposer/hwc_copybitEngine.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. 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. + */ +#ifndef HWC_COPYBIT_ENGINE_H +#define HWC_COPYBIT_ENGINE_H + +namespace qhwc { +class CopybitEngine { +public: + ~CopybitEngine(); + // API to get copybit engine(non static) + struct copybit_device_t *getEngine(); + // API to get singleton + static CopybitEngine* getInstance(); + +private: + CopybitEngine(); + struct copybit_device_t *sEngine; + static CopybitEngine* sInstance; // singleton +}; + +}; //namespace qhwc + +#endif //HWC_COPYBIT_ENGINE_H diff --git a/libhwcomposer/hwc_uimirror.cpp b/libhwcomposer/hwc_uimirror.cpp index f5cf3e6..4540be8 100644 --- a/libhwcomposer/hwc_uimirror.cpp +++ b/libhwcomposer/hwc_uimirror.cpp @@ -73,11 +73,11 @@ bool UIMirrorOverlay::configure(hwc_context_t *ctx, hwc_layer_list_t *list) overlay::Overlay& ov = *(ctx->mOverlay); // Set overlay state ov.setState(sState); - framebuffer_device_t *fbDev = ctx->fbDev; + framebuffer_device_t *fbDev = ctx->mFbDevice->getFb(); if(fbDev) { private_module_t* m = reinterpret_cast( fbDev->common.module); - int alignedW = ALIGN(m->info.xres, 32); + int alignedW = ALIGN_TO(m->info.xres, 32); private_handle_t const* hnd = reinterpret_cast(m->framebuffer); @@ -143,7 +143,7 @@ bool UIMirrorOverlay::draw(hwc_context_t *ctx) overlay::Overlay& ov = *(ctx->mOverlay); ovutils::eOverlayState state = ov.getState(); ovutils::eDest dest = ovutils::OV_PIPE_ALL; - framebuffer_device_t *fbDev = ctx->fbDev; + framebuffer_device_t *fbDev = ctx->mFbDevice->getFb(); if(fbDev) { private_module_t* m = reinterpret_cast( fbDev->common.module); diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp index ea2fe66..ae5c526 100644 --- a/libhwcomposer/hwc_utils.cpp +++ b/libhwcomposer/hwc_utils.cpp @@ -19,11 +19,11 @@ #include "mdp_version.h" #include "hwc_video.h" #include "hwc_ext_observer.h" +#include "hwc_copybit.h" namespace qhwc { void initContext(hwc_context_t *ctx) { //XXX: target specific initializations here - openFramebufferDevice(ctx); ctx->mOverlay = overlay::Overlay::getInstance(); ctx->qbuf = new QueuedBufferStore(); ctx->mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion(); @@ -32,6 +32,9 @@ void initContext(hwc_context_t *ctx) ctx->mExtDisplayObserver = ExtDisplayObserver::getInstance(); ctx->mExtDisplayObserver->setHwcContext(ctx); + ctx->mFbDevice = FbDevice::getInstance(); + ctx->mCopybitEngine = CopybitEngine::getInstance(); + CopyBit::openEglLibAndGethandle(); } void closeContext(hwc_context_t *ctx) @@ -41,23 +44,19 @@ void closeContext(hwc_context_t *ctx) ctx->mOverlay = NULL; } - if(ctx->fbDev) { - framebuffer_close(ctx->fbDev); - ctx->fbDev = NULL; + if(ctx->mCopybitEngine) { + delete ctx->mCopybitEngine; + ctx->mCopybitEngine = NULL; + } + if(ctx->mFbDevice) { + delete ctx->mFbDevice; + ctx->mFbDevice = NULL; } - if(ctx->qbuf) { delete ctx->qbuf; ctx->qbuf = NULL; } -} - -// Opens Framebuffer device -void openFramebufferDevice(hwc_context_t *ctx) { - hw_module_t const *module; - if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { - framebuffer_open(module, &(ctx->fbDev)); - } + CopyBit::closeEglLib(); } void dumpLayer(hwc_layer_t const* l) @@ -102,6 +101,7 @@ void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list) } VideoOverlay::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip); + CopyBit::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip); ctx->numHwLayers = list->numHwLayers; return; @@ -163,4 +163,33 @@ void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst, } } +//FbDevice class functions +FbDevice* FbDevice::sInstance = 0;; +struct framebuffer_device_t* FbDevice::getFb() { + return sFb; +} + +FbDevice* FbDevice::getInstance() { + if(sInstance == NULL) + sInstance = new FbDevice(); + return sInstance; +} + +FbDevice::FbDevice(){ + hw_module_t const *module; + if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { + framebuffer_open(module, &sFb); + } else { + ALOGE("FATAL ERROR: framebuffer open failed."); + } +} +FbDevice::~FbDevice() +{ + if(sFb) + { + framebuffer_close(sFb); + sFb = NULL; + } +} + };//namespace diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h index 2ee7188..0bf30c9 100644 --- a/libhwcomposer/hwc_utils.h +++ b/libhwcomposer/hwc_utils.h @@ -26,16 +26,33 @@ #include #include #include +#include +#include #include #include "hwc_qbuf.h" +#include -#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) +#define ALIGN_TO(x, align) (((x) + ((align)-1)) & ~((align)-1)) #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) +#define FINAL_TRANSFORM_MASK 0x000F struct hwc_context_t; namespace qhwc { +enum external_display_type { + EXT_TYPE_NONE, + EXT_TYPE_HDMI, + EXT_TYPE_WIFI +}; +enum HWCCompositionType { + HWC_USE_GPU = HWC_FRAMEBUFFER, // This layer is to be handled by + // Surfaceflinger + HWC_USE_OVERLAY = HWC_OVERLAY, // This layer is to be handled by the overlay + HWC_USE_COPYBIT // This layer is to be handled by copybit +}; + + class ExtDisplayObserver; // ----------------------------------------------------------------------------- // Utility functions - implemented in hwc_utils.cpp @@ -43,7 +60,6 @@ void dumpLayer(hwc_layer_t const* l); void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list); void initContext(hwc_context_t *ctx); void closeContext(hwc_context_t *ctx); -void openFramebufferDevice(hwc_context_t *ctx); //Crops source buffer against destination and FB boundaries void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst, const int fbWidth, const int fbHeight); @@ -62,6 +78,28 @@ static inline bool isYuvBuffer(const private_handle_t* hnd) { static inline bool isBufferLocked(const private_handle_t* hnd) { return (hnd && (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags)); } +// ----------------------------------------------------------------------------- +// Copybit specific - inline or implemented in hwc_copybit.cpp +typedef EGLClientBuffer (*functype_eglGetRenderBufferANDROID) ( + EGLDisplay dpy, + EGLSurface draw); +typedef EGLSurface (*functype_eglGetCurrentSurface)(EGLint readdraw); + +// ----------------------------------------------------------------------------- +// Singleton for Framebuffer device +class FbDevice{ +public: + ~FbDevice(); + // API to get Fb device(non static) + struct framebuffer_device_t *getFb(); + // API to get singleton + static FbDevice* getInstance(); + +private: + FbDevice(); + struct framebuffer_device_t *sFb; + static FbDevice* sInstance; // singleton +}; }; //qhwc namespace @@ -77,7 +115,10 @@ struct hwc_context_t { int overlayInUse; //Framebuffer device - framebuffer_device_t *fbDev; + qhwc::FbDevice* mFbDevice; + + //Copybit Engine + qhwc::CopybitEngine* mCopybitEngine; //Overlay object - NULL for non overlay devices overlay::Overlay *mOverlay; diff --git a/libhwcomposer/hwc_video.cpp b/libhwcomposer/hwc_video.cpp index 525d662..180ab86 100644 --- a/libhwcomposer/hwc_video.cpp +++ b/libhwcomposer/hwc_video.cpp @@ -33,6 +33,10 @@ bool VideoOverlay::sIsLayerSkip = false; //Cache stats, figure out the state, config overlay bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { sIsModeOn = false; + if(!ctx->hasOverlay) { + ALOGD_IF(VIDEO_DEBUG,"%s, this hw doesnt support overlay", __FUNCTION__); + return false; + } chooseState(ctx); //if the state chosen above is CLOSED, skip this block. if(sState != ovutils::OV_CLOSED) {