From a709f0300c238042a33c4640d4321ea3475f12f2 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Mon, 7 Mar 2011 17:31:51 -0800 Subject: [PATCH] libgralloc-qsd8k: Initial gralloc commit Update the gralloc HAL to match commit: commit 4d3c9ca6fabf2b0111ef6b567df7d244e124b9c2 Author: Arun Kumar K.R Date: Fri Dec 17 13:14:58 2010 -0800 libgralloc-qsd8k: Add support for non-aligned width on HDMI While creating overlay channel for HDMI consider the aligned width and set the crop rectangle to the actual width and height. Change-Id: I8858d71bb10b2be4c57edb605b5da680f53051dc --- libgralloc-qsd8k/Android.mk | 15 + libgralloc-qsd8k/framebuffer.cpp | 506 ++++++++++++++++++++++++++++--- libgralloc-qsd8k/gpu.cpp | 60 +++- libgralloc-qsd8k/gpu.h | 2 + libgralloc-qsd8k/gr.h | 8 +- libgralloc-qsd8k/gralloc.cpp | 11 +- libgralloc-qsd8k/gralloc_priv.h | 143 ++++++++- libgralloc-qsd8k/mapper.cpp | 151 ++++++++- libgralloc-qsd8k/pmemalloc.cpp | 1 + 9 files changed, 830 insertions(+), 67 deletions(-) mode change 100644 => 100755 libgralloc-qsd8k/gralloc_priv.h mode change 100644 => 100755 libgralloc-qsd8k/mapper.cpp diff --git a/libgralloc-qsd8k/Android.mk b/libgralloc-qsd8k/Android.mk index b22541a..2c32796 100644 --- a/libgralloc-qsd8k/Android.mk +++ b/libgralloc-qsd8k/Android.mk @@ -31,8 +31,23 @@ LOCAL_SRC_FILES := \ LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM) LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\" + +ifneq (, $(filter msm7625_ffa msm7625_surf msm7627_ffa msm7627_surf msm7627_7x_ffa msm7627_7x_surf, $(QCOM_TARGET_PRODUCT))) +LOCAL_CFLAGS += -DTARGET_MSM7x27 +endif + +ifeq ($(TARGET_HAVE_HDMI_OUT),true) +LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../liboverlay +LOCAL_SHARED_LIBRARIES += liboverlay +endif + +ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true) +LOCAL_CFLAGS += -DUSE_ASHMEM +endif include $(BUILD_SHARED_LIBRARY) + # Build a host library for testing ifeq ($(HOST_OS),linux) include $(CLEAR_VARS) diff --git a/libgralloc-qsd8k/framebuffer.cpp b/libgralloc-qsd8k/framebuffer.cpp index 11b303a..99ec2ad 100644 --- a/libgralloc-qsd8k/framebuffer.cpp +++ b/libgralloc-qsd8k/framebuffer.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +31,7 @@ #include #include #include +#include #include #include @@ -41,12 +43,45 @@ #include "gralloc_priv.h" #include "gr.h" +#ifdef NO_SURFACEFLINGER_SWAPINTERVAL +#include +#endif + +#if defined(HDMI_DUAL_DISPLAY) +#define AS_1080_RATIO_H (4.25/100) // Default Action Safe vertical limit for 1080p +#define AS_1080_RATIO_W (4.25/100) // Default Action Safe horizontal limit for 1080p +#define AS_720_RATIO_H (6.0/100) // Default Action Safe vertical limit for 720p +#define AS_720_RATIO_W (4.25/100) // Default Action Safe horizontal limit for 720p +#define AS_480_RATIO_H (8.0/100) // Default Action Safe vertical limit for 480p +#define AS_480_RATIO_W (5.0/100) // Default Action Safe horizontal limit for 480p +#define HEIGHT_1080P 1080 +#define HEIGHT_720P 720 +#define HEIGHT_480P 480 +#define EVEN_OUT(x) if (x & 0x0001) {x--;} +using overlay::Overlay; +/** min of int a, b */ +static inline int min(int a, int b) { + return (ab) ? a : b; +} +/** align */ +static inline size_t ALIGN(size_t x, size_t align) { + return (x + align-1) & ~(align-1); +} +#endif /*****************************************************************************/ -// numbers of buffers for page flipping -#define NUM_BUFFERS 2 - +enum { + MDDI_PANEL = '1', + EBI2_PANEL = '2', + LCDC_PANEL = '3', + EXT_MDDI_PANEL = '4', + TV_PANEL = '5' +}; enum { PAGE_FLIP = 0x00000001, @@ -57,6 +92,7 @@ struct fb_context_t { framebuffer_device_t device; }; +static int neworientation; /*****************************************************************************/ static void @@ -68,9 +104,12 @@ static int fb_setSwapInterval(struct framebuffer_device_t* dev, int interval) { fb_context_t* ctx = (fb_context_t*)dev; + private_module_t* m = reinterpret_cast( + dev->common.module); if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval) return -EINVAL; - // FIXME: implement fb_setSwapInterval + + m->swapInterval = interval; return 0; } @@ -89,38 +128,341 @@ static int fb_setUpdateRect(struct framebuffer_device_t* dev, return 0; } +static void *disp_loop(void *ptr) +{ + struct qbuf_t nxtBuf; + static int cur_buf=-1; + private_module_t *m = reinterpret_cast(ptr); + + while (1) { + pthread_mutex_lock(&(m->qlock)); + + // wait (sleep) while display queue is empty; + if (m->disp.isEmpty()) { + pthread_cond_wait(&(m->qpost),&(m->qlock)); + } + + // dequeue next buff to display and lock it + nxtBuf = m->disp.getHeadValue(); + m->disp.pop(); + pthread_mutex_unlock(&(m->qlock)); + + // post buf out to display synchronously + private_handle_t const* hnd = reinterpret_cast + (nxtBuf.buf); + const size_t offset = hnd->base - m->framebuffer->base; + m->info.activate = FB_ACTIVATE_VBL; + m->info.yoffset = offset / m->finfo.line_length; + +#if defined(HDMI_DUAL_DISPLAY) + pthread_mutex_lock(&m->overlayLock); + m->orientation = neworientation; + m->currentOffset = offset; + pthread_cond_signal(&(m->overlayPost)); + pthread_mutex_unlock(&m->overlayLock); +#endif + if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) { + LOGE("ERROR FBIOPUT_VSCREENINFO failed; frame not displayed"); + } + + if (cur_buf == -1) { + pthread_mutex_lock(&(m->avail[nxtBuf.idx].lock)); + m->avail[nxtBuf.idx].is_avail = true; + pthread_cond_signal(&(m->avail[nxtBuf.idx].cond)); + pthread_mutex_unlock(&(m->avail[nxtBuf.idx].lock)); + } else { + pthread_mutex_lock(&(m->avail[cur_buf].lock)); + m->avail[cur_buf].is_avail = true; + pthread_cond_signal(&(m->avail[cur_buf].cond)); + pthread_mutex_unlock(&(m->avail[cur_buf].lock)); + + } + cur_buf = nxtBuf.idx; + } + return NULL; +} + +#if defined(HDMI_DUAL_DISPLAY) +static void *hdmi_ui_loop(void *ptr) +{ + private_module_t* m = reinterpret_cast( + ptr); + while (1) { + pthread_mutex_lock(&m->overlayLock); + pthread_cond_wait(&(m->overlayPost), &(m->overlayLock)); + if (m->exitHDMIUILoop) { + pthread_mutex_unlock(&m->overlayLock); + return NULL; + } + float asWidthRatio = m->actionsafeWidthRatio/100.0f; + float asHeightRatio = m->actionsafeHeightRatio/100.0f; + + if (m->pobjOverlay) { + Overlay* pTemp = m->pobjOverlay; + if (!m->enableHDMIOutput) + pTemp->closeChannel(); + else if (m->enableHDMIOutput && !m->videoOverlay) { + if (!pTemp->isChannelUP()) { + int alignedW = ALIGN(m->info.xres, 32); + if (pTemp->startChannel(alignedW, m->info.yres, + m->fbFormat, 1, false, true)) { + pTemp->setFd(m->framebuffer->fd); + pTemp->setCrop(0, 0, m->info.xres, m->info.yres); + } else + pTemp->closeChannel(); + } + + if (pTemp->isChannelUP()) { + int width = pTemp->getFBWidth(); + int height = pTemp->getFBHeight(); + int aswidth = width, asheight = height; + int final_width = width, final_height = height; + int x = 0, y = 0; // Used for calculating normal x,y co-ordinates + int x1 = 0, y1 = 0; // Action safe x, y co-ordinates + int xx = 0, yy = 0; // Final x, y co-ordinates + int fbwidth = m->info.xres, fbheight = m->info.yres; + float defaultASWidthRatio = 0.0f, defaultASHeightRatio = 0.0f; + if(HEIGHT_1080P == height) { + defaultASHeightRatio = AS_1080_RATIO_H; + defaultASWidthRatio = AS_1080_RATIO_W; + } else if(HEIGHT_720P == height) { + defaultASHeightRatio = AS_720_RATIO_H; + defaultASWidthRatio = AS_720_RATIO_W; + } else if(HEIGHT_480P == height) { + defaultASHeightRatio = AS_480_RATIO_H; + defaultASWidthRatio = AS_480_RATIO_W; + } + if(asWidthRatio <= 0.0f) + asWidthRatio = defaultASWidthRatio; + if(asHeightRatio <= 0.0f) + asHeightRatio = defaultASHeightRatio; + + aswidth = (int)((float)width - (float)(width * asWidthRatio)); + asheight = (int)((float)height - (float)(height * asHeightRatio)); + x1 = (int)(width * asWidthRatio) / 2; + y1 = (int)(height * asHeightRatio) / 2; + int rot = m->orientation; + if (fbwidth < fbheight) { + switch(rot) { + // ROT_0 + case 0: + // ROT_180 + case HAL_TRANSFORM_ROT_180: + x = (width - fbwidth) / 2; + if (x < 0) + x = 0; + if (fbwidth < width) + width = fbwidth; + if (fbheight < height) + height = fbheight; + if(rot == HAL_TRANSFORM_ROT_180) + rot = OVERLAY_TRANSFORM_ROT_180; + else + rot = 0; + break; + // ROT_90 + case HAL_TRANSFORM_ROT_90: + rot = OVERLAY_TRANSFORM_ROT_270; + break; + // ROT_270 + case HAL_TRANSFORM_ROT_270: + rot = OVERLAY_TRANSFORM_ROT_90; + break; + } + } + else if (fbwidth > fbheight) { + switch(rot) { + // ROT_0 + case 0: + rot = 0; + break; + // ROT_180 + case HAL_TRANSFORM_ROT_180: + rot = OVERLAY_TRANSFORM_ROT_180; + break; + // ROT_90 + case HAL_TRANSFORM_ROT_90: + // ROT_270 + case HAL_TRANSFORM_ROT_270: + //Swap width and height + int t = fbwidth; + fbwidth = fbheight; + fbheight = t; + x = (width - fbwidth) / 2; + if (x < 0) + x = 0; + if (fbwidth < width) + width = fbwidth; + if (fbheight < height) + height = fbheight; + if(rot == HAL_TRANSFORM_ROT_90) + rot = OVERLAY_TRANSFORM_ROT_270; + else + rot = OVERLAY_TRANSFORM_ROT_90; + break; + } + } + pTemp->setParameter(OVERLAY_TRANSFORM, + rot); + // Calculate the interection of final destination parameters + // Intersection of Action Safe rect and the orig rect will give the final dest rect + xx = max(x1, x); + yy = max(y1, y); + final_width = min((x1+aswidth), (x+width))- xx; + final_height = min((y1+asheight), (y+height))- yy; + EVEN_OUT(xx); + EVEN_OUT(yy); + EVEN_OUT(final_width); + EVEN_OUT(final_height); + pTemp->setPosition(xx, yy, final_width, final_height); + pTemp->queueBuffer(m->currentOffset); + } + } + else + pTemp->closeChannel(); + } + pthread_mutex_unlock(&m->overlayLock); + } + return NULL; +} + +static int fb_videoOverlayStarted(struct framebuffer_device_t* dev, int started) +{ + private_module_t* m = reinterpret_cast( + dev->common.module); + pthread_mutex_lock(&m->overlayLock); + Overlay* pTemp = m->pobjOverlay; + if (started && pTemp) { + pTemp->closeChannel(); + m->videoOverlay = true; + pthread_cond_signal(&(m->overlayPost)); + } + else { + m->videoOverlay = false; + pthread_cond_signal(&(m->overlayPost)); + } + pthread_mutex_unlock(&m->overlayLock); + return 0; +} + +static int fb_enableHDMIOutput(struct framebuffer_device_t* dev, int enable) +{ + private_module_t* m = reinterpret_cast( + dev->common.module); + pthread_mutex_lock(&m->overlayLock); + Overlay* pTemp = m->pobjOverlay; + if (!enable && pTemp) + pTemp->closeChannel(); + m->enableHDMIOutput = enable; + pthread_cond_signal(&(m->overlayPost)); + pthread_mutex_unlock(&m->overlayLock); + return 0; +} + +static int fb_setActionSafeWidthRatio(struct framebuffer_device_t* dev, float asWidthRatio) +{ + private_module_t* m = reinterpret_cast( + dev->common.module); + pthread_mutex_lock(&m->overlayLock); + m->actionsafeWidthRatio = asWidthRatio; + pthread_mutex_unlock(&m->overlayLock); + return 0; +} + +static int fb_setActionSafeHeightRatio(struct framebuffer_device_t* dev, float asHeightRatio) +{ + private_module_t* m = reinterpret_cast( + dev->common.module); + pthread_mutex_lock(&m->overlayLock); + m->actionsafeHeightRatio = asHeightRatio; + pthread_mutex_unlock(&m->overlayLock); + return 0; +} +static int fb_orientationChanged(struct framebuffer_device_t* dev, int orientation) +{ + private_module_t* m = reinterpret_cast( + dev->common.module); + pthread_mutex_lock(&m->overlayLock); + neworientation = orientation; + pthread_mutex_unlock(&m->overlayLock); + return 0; +} +#endif + static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) { if (private_handle_t::validate(buffer) < 0) return -EINVAL; + int nxtIdx; + bool reuse; + struct qbuf_t qb; fb_context_t* ctx = (fb_context_t*)dev; private_handle_t const* hnd = reinterpret_cast(buffer); private_module_t* m = reinterpret_cast( dev->common.module); - - if (m->currentBuffer) { - m->base.unlock(&m->base, m->currentBuffer); - m->currentBuffer = 0; - } if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { - m->base.lock(&m->base, buffer, - private_module_t::PRIV_USAGE_LOCKED_FOR_POST, - 0, 0, m->info.xres, m->info.yres, NULL); + reuse = false; + nxtIdx = (m->currentIdx + 1) % NUM_BUFFERS; - const size_t offset = hnd->base - m->framebuffer->base; - m->info.activate = FB_ACTIVATE_VBL; - m->info.yoffset = offset / m->finfo.line_length; - if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) { - LOGE("FBIOPUT_VSCREENINFO failed"); - m->base.unlock(&m->base, buffer); - return -errno; + if (m->swapInterval == 0) { + // if SwapInterval = 0 and no buffers available then reuse + // current buf for next rendering so don't post new buffer + if (pthread_mutex_trylock(&(m->avail[nxtIdx].lock))) { + reuse = true; + } else { + if (! m->avail[nxtIdx].is_avail) + reuse = true; + pthread_mutex_unlock(&(m->avail[nxtIdx].lock)); + } } - m->currentBuffer = buffer; - + + if(!reuse){ + // unlock previous ("current") Buffer and lock the new buffer + m->base.lock(&m->base, buffer, + private_module_t::PRIV_USAGE_LOCKED_FOR_POST, + 0,0, m->info.xres, m->info.yres, NULL); + + // post/queue the new buffer + pthread_mutex_lock(&(m->avail[nxtIdx].lock)); + m->avail[nxtIdx].is_avail = false; + pthread_mutex_unlock(&(m->avail[nxtIdx].lock)); + + qb.idx = nxtIdx; + qb.buf = buffer; + pthread_mutex_lock(&(m->qlock)); + m->disp.push(qb); + pthread_cond_signal(&(m->qpost)); + pthread_mutex_unlock(&(m->qlock)); + + // LCDC: after new buffer grabbed by MDP can unlock previous + // (current) buffer + if (m->currentBuffer) { + if (m->swapInterval != 0) { + pthread_mutex_lock(&(m->avail[m->currentIdx].lock)); + if (! m->avail[m->currentIdx].is_avail) { + pthread_cond_wait(&(m->avail[m->currentIdx].cond), + &(m->avail[m->currentIdx].lock)); + m->avail[m->currentIdx].is_avail = true; + } + pthread_mutex_unlock(&(m->avail[m->currentIdx].lock)); + } + m->base.unlock(&m->base, m->currentBuffer); + } + m->currentBuffer = buffer; + m->currentIdx = nxtIdx; + } else { + if (m->currentBuffer) + m->base.unlock(&m->base, m->currentBuffer); + m->base.lock(&m->base, buffer, + private_module_t::PRIV_USAGE_LOCKED_FOR_POST, + 0,0, m->info.xres, m->info.yres, NULL); + m->currentBuffer = buffer; + } + } else { void* fb_vaddr; void* buffer_vaddr; @@ -206,28 +548,45 @@ int mapFrameBufferLocked(struct private_module_t* module) * big-endian byte order if bits_per_pixel is greater than 8. */ - /* - * Explicitly request RGBA_8888 - */ - info.bits_per_pixel = 32; - info.red.offset = 24; - info.red.length = 8; - info.green.offset = 16; - info.green.length = 8; - info.blue.offset = 8; - info.blue.length = 8; - info.transp.offset = 0; - info.transp.length = 0; - - /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we do - * not use the MDP for composition (i.e. hw composition == 0), ask for - * RGBA instead of RGBX. */ - char property[PROPERTY_VALUE_MAX]; - if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0) - module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888; - else - module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888; + if(info.bits_per_pixel == 32) { + /* + * Explicitly request RGBA_8888 + */ + info.bits_per_pixel = 32; + info.red.offset = 24; + info.red.length = 8; + info.green.offset = 16; + info.green.length = 8; + info.blue.offset = 8; + info.blue.length = 8; + info.transp.offset = 0; + info.transp.length = 8; + /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we do + * not use the MDP for composition (i.e. hw composition == 0), ask for + * RGBA instead of RGBX. */ + char property[PROPERTY_VALUE_MAX]; + if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0) + module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888; + else if(property_get("debug.composition.type", property, NULL) > 0 && (strncmp(property, "mdp", 3) == 0)) + module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888; + else + module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888; + } else { + /* + * Explicitly request 5/6/5 + */ + info.bits_per_pixel = 16; + info.red.offset = 11; + info.red.length = 5; + info.green.offset = 5; + info.green.length = 6; + info.blue.offset = 0; + info.blue.length = 5; + info.transp.offset = 0; + info.transp.length = 0; + module->fbFormat = HAL_PIXEL_FORMAT_RGB_565; + } /* * Request NUM_BUFFERS screens (at lest 2 for page flipping) */ @@ -320,6 +679,38 @@ int mapFrameBufferLocked(struct private_module_t* module) module->ydpi = ydpi; module->fps = fps; +#ifdef NO_SURFACEFLINGER_SWAPINTERVAL + char pval[PROPERTY_VALUE_MAX]; + property_get("debug.gr.swapinterval", pval, "1"); + module->swapInterval = atoi(pval); + if (module->swapInterval < private_module_t::PRIV_MIN_SWAP_INTERVAL || + module->swapInterval > private_module_t::PRIV_MAX_SWAP_INTERVAL) { + module->swapInterval = 1; + LOGW("Out of range (%d to %d) value for debug.gr.swapinterval, using 1", + private_module_t::PRIV_MIN_SWAP_INTERVAL, + private_module_t::PRIV_MAX_SWAP_INTERVAL); + } + +#else + /* when surfaceflinger supports swapInterval then can just do this */ + module->swapInterval = 1; +#endif + + module->currentIdx = -1; + pthread_cond_init(&(module->qpost), NULL); + pthread_mutex_init(&(module->qlock), NULL); + for (i = 0; i < NUM_BUFFERS; i++) { + pthread_mutex_init(&(module->avail[i].lock), NULL); + pthread_cond_init(&(module->avail[i].cond), NULL); + module->avail[i].is_avail = true; + } + + /* create display update thread */ + pthread_t thread1; + if (pthread_create(&thread1, NULL, &disp_loop, (void *) module)) { + return -errno; + } + /* * map the framebuffer */ @@ -339,6 +730,18 @@ int mapFrameBufferLocked(struct private_module_t* module) } module->framebuffer->base = intptr_t(vaddr); memset(vaddr, 0, fbSize); + +#if defined(HDMI_DUAL_DISPLAY) + /* Overlay for HDMI*/ + pthread_mutex_init(&(module->overlayLock), NULL); + pthread_cond_init(&(module->overlayPost), NULL); + module->pobjOverlay = new Overlay(); + module->currentOffset = 0; + module->exitHDMIUILoop = false; + pthread_t hdmiUIThread; + pthread_create(&hdmiUIThread, NULL, &hdmi_ui_loop, (void *) module); +#endif + return 0; } @@ -355,6 +758,14 @@ static int mapFrameBuffer(struct private_module_t* module) static int fb_close(struct hw_device_t *dev) { fb_context_t* ctx = (fb_context_t*)dev; +#if defined(HDMI_DUAL_DISPLAY) + private_module_t* m = reinterpret_cast( + ctx->device.common.module); + pthread_mutex_lock(&m->overlayLock); + m->exitHDMIUILoop = true; + pthread_cond_signal(&(m->overlayPost)); + pthread_mutex_unlock(&m->overlayLock); +#endif if (ctx) { free(ctx); } @@ -384,6 +795,13 @@ int fb_device_open(hw_module_t const* module, const char* name, dev->device.post = fb_post; dev->device.setUpdateRect = 0; dev->device.compositionComplete = fb_compositionComplete; +#if defined(HDMI_DUAL_DISPLAY) + dev->device.orientationChanged = fb_orientationChanged; + dev->device.videoOverlayStarted = fb_videoOverlayStarted; + dev->device.enableHDMIOutput = fb_enableHDMIOutput; + dev->device.setActionSafeWidthRatio = fb_setActionSafeWidthRatio; + dev->device.setActionSafeHeightRatio = fb_setActionSafeHeightRatio; +#endif private_module_t* m = (private_module_t*)module; status = mapFrameBuffer(m); @@ -397,8 +815,8 @@ int fb_device_open(hw_module_t const* module, const char* name, const_cast(dev->device.xdpi) = m->xdpi; const_cast(dev->device.ydpi) = m->ydpi; const_cast(dev->device.fps) = m->fps; - const_cast(dev->device.minSwapInterval) = 1; - const_cast(dev->device.maxSwapInterval) = 1; + const_cast(dev->device.minSwapInterval) = private_module_t::PRIV_MIN_SWAP_INTERVAL; + const_cast(dev->device.maxSwapInterval) = private_module_t::PRIV_MAX_SWAP_INTERVAL; if (m->finfo.reserved[0] == 0x5444 && m->finfo.reserved[1] == 0x5055) { diff --git a/libgralloc-qsd8k/gpu.cpp b/libgralloc-qsd8k/gpu.cpp index 90ff445..a2ccd16 100644 --- a/libgralloc-qsd8k/gpu.cpp +++ b/libgralloc-qsd8k/gpu.cpp @@ -79,7 +79,7 @@ int gpu_context_t::gralloc_alloc_framebuffer_locked(size_t size, int usage, // create a "fake" handles for it intptr_t vaddr = intptr_t(m->framebuffer->base); - private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size, + private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), bufferSize, private_handle_t::PRIV_FLAGS_USES_PMEM | private_handle_t::PRIV_FLAGS_FRAMEBUFFER); @@ -110,6 +110,46 @@ int gpu_context_t::gralloc_alloc_framebuffer(size_t size, int usage, return err; } +int gpu_context_t::alloc_ashmem_buffer(size_t size, unsigned int postfix, void** pBase, + int* pOffset, int* pFd) +{ + int err = 0; + int fd = -1; + void* base = 0; + int offset = 0; + + char name[ASHMEM_NAME_LEN]; + snprintf(name, ASHMEM_NAME_LEN, "gralloc-buffer-%x", postfix); + int prot = PROT_READ | PROT_WRITE; + fd = ashmem_create_region(name, size); + if (fd < 0) { + LOGE("couldn't create ashmem (%s)", strerror(errno)); + err = -errno; + } else { + if (ashmem_set_prot_region(fd, prot) < 0) { + LOGE("ashmem_set_prot_region(fd=%d, prot=%x) failed (%s)", + fd, prot, strerror(errno)); + close(fd); + err = -errno; + } else { + base = mmap(0, size, prot, MAP_SHARED|MAP_POPULATE|MAP_LOCKED, fd, 0); + if (base == MAP_FAILED) { + LOGE("alloc mmap(fd=%d, size=%d, prot=%x) failed (%s)", + fd, size, prot, strerror(errno)); + close(fd); + err = -errno; + } else { + memset((char*)base + offset, 0, size); + } + } + } + if(err == 0) { + *pFd = fd; + *pBase = base; + *pOffset = offset; + } + return err; +} int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, buffer_handle_t* pHandle) { @@ -123,7 +163,7 @@ int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, buffer_handle_t* int lockState = 0; size = roundUpToPageSize(size); - +#ifndef USE_ASHMEM if (usage & GRALLOC_USAGE_HW_TEXTURE) { // enable pmem in that case, so our software GL can fallback to // the copybit module. @@ -133,15 +173,25 @@ int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, buffer_handle_t* if (usage & GRALLOC_USAGE_HW_2D) { flags |= private_handle_t::PRIV_FLAGS_USES_PMEM; } - +#else + if (usage & GRALLOC_USAGE_PRIVATE_PMEM){ + flags |= private_handle_t::PRIV_FLAGS_USES_PMEM; + } +#endif if (usage & GRALLOC_USAGE_PRIVATE_PMEM_ADSP) { flags |= private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP; flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM; } private_module_t* m = reinterpret_cast(common.module); - - if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) != 0 || + if((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) == 0 && + (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) == 0) { + flags |= private_handle_t::PRIV_FLAGS_USES_ASHMEM; + err = alloc_ashmem_buffer(size, (unsigned int)pHandle, &base, &offset, &fd); + if(err >= 0) + lockState |= private_handle_t::LOCK_STATE_MAPPED; + } + else if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) != 0 || (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0) { PmemAllocator* pma = 0; diff --git a/libgralloc-qsd8k/gpu.h b/libgralloc-qsd8k/gpu.h index 5da7b6a..5449999 100644 --- a/libgralloc-qsd8k/gpu.h +++ b/libgralloc-qsd8k/gpu.h @@ -71,6 +71,8 @@ class gpu_context_t : public alloc_device_t { Deps& deps; PmemAllocator& pmemAllocator; PmemAllocator& pmemAdspAllocator; + int alloc_ashmem_buffer(size_t size, unsigned int postfix, void** pBase, + int* pOffset, int* pFd); }; #endif // GRALLOC_QSD8K_GPU_H diff --git a/libgralloc-qsd8k/gr.h b/libgralloc-qsd8k/gr.h index 1775bfa..49a0513 100644 --- a/libgralloc-qsd8k/gr.h +++ b/libgralloc-qsd8k/gr.h @@ -40,9 +40,15 @@ inline size_t roundUpToPageSize(size_t x) { return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1); } +#define FALSE 0 +#define TRUE 1 + int mapFrameBufferLocked(struct private_module_t* module); int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd); - +size_t calculateBufferSize(int width, int height, int format); +int decideBufferHandlingMechanism(int format, const char *compositionUsed, + int hasBlitEngine, int *needConversion, + int *useBufferDirectly); /*****************************************************************************/ class Locker { diff --git a/libgralloc-qsd8k/gralloc.cpp b/libgralloc-qsd8k/gralloc.cpp index bf60324..a0123d1 100644 --- a/libgralloc-qsd8k/gralloc.cpp +++ b/libgralloc-qsd8k/gralloc.cpp @@ -65,11 +65,20 @@ class PmemAllocatorDepsDeviceImpl : public PmemUserspaceAllocator::Deps, public PmemKernelAllocator::Deps { virtual size_t getPmemTotalSize(int fd, size_t* size) { + int err = 0; +#ifndef TARGET_MSM7x27 pmem_region region; - int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®ion); + err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®ion); if (err == 0) { *size = region.len; } +#else +#ifdef USE_ASHMEM + *size = m->info.xres * m->info.yres * 2 * 2; +#else + *size = 23<<20; //23MB for 7x27 +#endif +#endif return err; } diff --git a/libgralloc-qsd8k/gralloc_priv.h b/libgralloc-qsd8k/gralloc_priv.h old mode 100644 new mode 100755 index c573941..650ac6c --- a/libgralloc-qsd8k/gralloc_priv.h +++ b/libgralloc-qsd8k/gralloc_priv.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,12 +30,98 @@ #include +#if defined(__cplusplus) && defined(HDMI_DUAL_DISPLAY) +#include "overlayLib.h" +using namespace overlay; +#endif + enum { /* gralloc usage bit indicating a pmem_adsp allocation should be used */ GRALLOC_USAGE_PRIVATE_PMEM_ADSP = GRALLOC_USAGE_PRIVATE_0, + GRALLOC_USAGE_PRIVATE_PMEM = GRALLOC_USAGE_PRIVATE_1, }; +#define NUM_BUFFERS 2 +#define NO_SURFACEFLINGER_SWAPINTERVAL +#define INTERLACE_MASK 0x80 /*****************************************************************************/ +#ifdef __cplusplus +template +struct Node +{ + T data; + Node *next; +}; + +template +class Queue +{ +public: + Queue(): front(NULL), back(NULL), len(0) {dummy = new T;} + ~Queue() + { + clear(); + delete dummy; + } + void push(const T& item) //add an item to the back of the queue + { + if(len != 0) { //if the queue is not empty + back->next = new Node; //create a new node + back = back->next; //set the new node as the back node + back->data = item; + back->next = NULL; + } else { + back = new Node; + back->data = item; + back->next = NULL; + front = back; + } + len++; + } + void pop() //remove the first item from the queue + { + if (isEmpty()) + return; //if the queue is empty, no node to dequeue + T item = front->data; + Node *tmp = front; + front = front->next; + delete tmp; + if(front == NULL) //if the queue is empty, update the back pointer + back = NULL; + len--; + return; + } + T& getHeadValue() const //return the value of the first item in the queue + { //without modification to the structure + if (isEmpty()) { + LOGE("Error can't get head of empty queue"); + return *dummy; + } + return front->data; + } + + bool isEmpty() const //returns true if no elements are in the queue + { + return (front == NULL); + } + + size_t size() const //returns the amount of elements in the queue + { + return len; + } + +private: + Node *front; + Node *back; + size_t len; + void clear() + { + while (!isEmpty()) + pop(); + } + T *dummy; +}; +#endif enum { /* OEM specific HAL formats */ @@ -50,7 +137,21 @@ enum { HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x109, HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x10A, HAL_PIXEL_FORMAT_YCrCb_422_SP = 0x10B, - HAL_PIXEL_FORMAT_YCrCb_420_SP_INTERLACE = 0x10C, + HAL_PIXEL_FORMAT_R_8 = 0x10D, + HAL_PIXEL_FORMAT_RG_88 = 0x10E, + HAL_PIXEL_FORMAT_INTERLACE = 0x180, + +}; + +/* possible formats for 3D content*/ +enum { + HAL_NO_3D = 0x00, + HAL_3D_IN_LR_SIDE = 0x10000, + HAL_3D_IN_LR_TOP = 0x20000, + HAL_3D_IN_LR_INTERLEAVE = 0x40000, + HAL_3D_OUT_LR_SIDE = 0x1, + HAL_3D_OUT_LR_TOP = 0x2, + HAL_3D_OUT_LR_INTERLEAVE = 0x4 }; /*****************************************************************************/ @@ -59,6 +160,19 @@ struct private_module_t; struct private_handle_t; struct PmemAllocator; +struct qbuf_t { + buffer_handle_t buf; + int idx; +}; + +struct avail_t { + pthread_mutex_t lock; + pthread_cond_t cond; +#ifdef __cplusplus + bool is_avail; +#endif +}; + struct private_module_t { gralloc_module_t base; @@ -75,11 +189,33 @@ struct private_module_t { float xdpi; float ydpi; float fps; - + int swapInterval; +#ifdef __cplusplus + Queue disp; // non-empty when buffer is ready for display +#endif + int currentIdx; + struct avail_t avail[NUM_BUFFERS]; + pthread_mutex_t qlock; + pthread_cond_t qpost; + enum { // flag to indicate we'll post this buffer - PRIV_USAGE_LOCKED_FOR_POST = 0x80000000 + PRIV_USAGE_LOCKED_FOR_POST = 0x80000000, + PRIV_MIN_SWAP_INTERVAL = 0, + PRIV_MAX_SWAP_INTERVAL = 1, }; +#if defined(__cplusplus) && defined(HDMI_DUAL_DISPLAY) + Overlay* pobjOverlay; + int orientation; + bool videoOverlay; + uint32_t currentOffset; + bool enableHDMIOutput; + bool exitHDMIUILoop; + float actionsafeWidthRatio; + float actionsafeHeightRatio; + pthread_mutex_t overlayLock; + pthread_cond_t overlayPost; +#endif }; /*****************************************************************************/ @@ -96,6 +232,7 @@ struct private_handle_t { PRIV_FLAGS_USES_PMEM = 0x00000002, PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004, PRIV_FLAGS_NEEDS_FLUSH = 0x00000008, + PRIV_FLAGS_USES_ASHMEM = 0x00000010, }; enum { diff --git a/libgralloc-qsd8k/mapper.cpp b/libgralloc-qsd8k/mapper.cpp old mode 100644 new mode 100755 index 26fadbc..9234c8d --- a/libgralloc-qsd8k/mapper.cpp +++ b/libgralloc-qsd8k/mapper.cpp @@ -25,9 +25,11 @@ #include #include #include +#include #include #include +#include #include #include @@ -35,7 +37,7 @@ #include #include "gralloc_priv.h" - +#include "gr.h" // we need this for now because pmem cannot mmap at an offset #define PMEM_HACK 1 @@ -55,13 +57,19 @@ static int gralloc_map(gralloc_module_t const* module, void** vaddr) { private_handle_t* hnd = (private_handle_t*)handle; + void *mappedAddress; if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { size_t size = hnd->size; #if PMEM_HACK size += hnd->offset; #endif - void* mappedAddress = mmap(0, size, + if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) { + mappedAddress = mmap(0, size, + PROT_READ|PROT_WRITE, MAP_SHARED | MAP_POPULATE, hnd->fd, 0); + } else { + mappedAddress = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0); + } if (mappedAddress == MAP_FAILED) { LOGE("Could not mmap handle %p, fd=%d (%s)", handle, hnd->fd, strerror(errno)); @@ -171,8 +179,8 @@ int terminateBuffer(gralloc_module_t const* module, if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) { // this buffer was mapped, unmap it now - if ((hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) || - (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP)) { + if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM || + hnd->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) { if (hnd->pid != getpid()) { // ... unless it's a "master" pmem buffer, that is a buffer // mapped in the process it's been allocated. @@ -239,12 +247,7 @@ int gralloc_lock(gralloc_module_t const* module, // if requesting sw write for non-framebuffer handles, flag for // flushing at unlock - const uint32_t pmemMask = - private_handle_t::PRIV_FLAGS_USES_PMEM | - private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP; - if ((usage & GRALLOC_USAGE_SW_WRITE_MASK) && - (hnd->flags & pmemMask) && !(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH; } @@ -279,12 +282,18 @@ int gralloc_unlock(gralloc_module_t const* module, int32_t current_value, new_value; if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) { - struct pmem_region region; int err; + if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) { + struct pmem_addr pmem_addr; + pmem_addr.vaddr = hnd->base; + pmem_addr.offset = hnd->offset; + pmem_addr.length = hnd->size; + err = ioctl( hnd->fd, PMEM_CLEAN_CACHES, &pmem_addr); + } else if ((hnd->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM)) { + unsigned long addr = hnd->base + hnd->offset; + err = ioctl(hnd->fd, ASHMEM_CACHE_CLEAN_RANGE, NULL); + } - region.offset = hnd->offset; - region.len = hnd->size; - err = ioctl(hnd->fd, PMEM_CACHE_FLUSH, ®ion); LOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x)\n", hnd, hnd->offset, hnd->size); hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH; @@ -347,12 +356,128 @@ int gralloc_perform(struct gralloc_module_t const* module, hnd->offset = offset; hnd->base = intptr_t(base) + offset; hnd->lockState = private_handle_t::LOCK_STATE_MAPPED; + hnd->gpuaddr = 0; *handle = (native_handle_t *)hnd; res = 0; break; } + case GRALLOC_MODULE_PERFORM_DECIDE_PUSH_BUFFER_HANDLING: { + int format = va_arg(args, int); + int width = va_arg(args, int); + int height = va_arg(args, int); + char *compositionUsed = va_arg(args, char*); + int hasBlitEngine = va_arg(args, int); + int *needConversion = va_arg(args, int*); + int *useBufferDirectly = va_arg(args, int*); + size_t *size = va_arg(args, size_t*); + *size = calculateBufferSize(width, height, format); + int conversion = 0; + int direct = 0; + res = decideBufferHandlingMechanism(format, compositionUsed, hasBlitEngine, + needConversion, useBufferDirectly); + break; + } + default: + break; } va_end(args); return res; } + +int decideBufferHandlingMechanism(int format, const char *compositionUsed, int hasBlitEngine, + int *needConversion, int *useBufferDirectly) +{ + *needConversion = FALSE; + *useBufferDirectly = FALSE; + if(compositionUsed == NULL) { + LOGE("null pointer"); + return -1; + } + + if(format == HAL_PIXEL_FORMAT_RGB_565) { + // Software video renderer gives the output in RGB565 format. + // This can be handled by all compositors + *needConversion = FALSE; + *useBufferDirectly = TRUE; + } else if(strncmp(compositionUsed, "cpu", 3) == 0){ + *needConversion = FALSE; + *useBufferDirectly = FALSE; + } else if(strncmp(compositionUsed, "gpu", 3) == 0) { + if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED + || format == HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO) { + *needConversion = FALSE; + *useBufferDirectly = TRUE; + } else if(hasBlitEngine) { + *needConversion = TRUE; + *useBufferDirectly = FALSE; + } + } else if ((strncmp(compositionUsed, "mdp", 3) == 0) || + (strncmp(compositionUsed, "c2d", 3) == 0)){ + if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP || + format == HAL_PIXEL_FORMAT_YCrCb_420_SP) { + *needConversion = FALSE; + *useBufferDirectly = TRUE; + } else if((strncmp(compositionUsed, "c2d", 3) == 0) && + format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) { + *needConversion = FALSE; + *useBufferDirectly = TRUE; + } else if(hasBlitEngine) { + *needConversion = TRUE; + *useBufferDirectly = FALSE; + } + } else { + LOGE("Invalid composition type %s", compositionUsed); + return -1; + } + return 0; +} + +size_t calculateBufferSize(int width, int height, int format) +{ + if(!width || !height) + return 0; + + size_t size = 0; + + switch (format) + { + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: { + int aligned_height = (height + 31) & ~31; + int pitch = (width + 127) & ~127; + size = pitch * aligned_height; + size = (size + 8191) & ~8191; + int secondPlaneOffset = size; + + aligned_height = ((height >> 1) + 31) & ~31; + size += pitch * aligned_height; + size = (size + 8191) & ~8191; + break; + } + case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: { + int aligned_height = (height + 31) & ~31; + int pitch = (width + 31) & ~31; + size = pitch * aligned_height; + size = (size + 4095) & ~4095; + int secondPlaneOffset = size; + + pitch = 2 * (((width >> 1) + 31) & ~31); + aligned_height = ((height >> 1) + 31) & ~31; + size += pitch * aligned_height; + size = (size + 4095) & ~4095; + break; + } + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP: { + /* Camera and video YUV 420 semi-planar buffers are allocated with + size equal to w * h * 1.5 */ + int aligned_width = (width + 15) & ~15; + int aligned_chroma_width = ((width/2) + 15) & ~15; + size = (aligned_width * height) + ((aligned_chroma_width * height/2) *2); + break; + } + default: + break; + } + return size; +} diff --git a/libgralloc-qsd8k/pmemalloc.cpp b/libgralloc-qsd8k/pmemalloc.cpp index e42e898..91dc527 100644 --- a/libgralloc-qsd8k/pmemalloc.cpp +++ b/libgralloc-qsd8k/pmemalloc.cpp @@ -181,6 +181,7 @@ int PmemUserspaceAllocator::alloc_pmem_buffer(size_t size, int usage, } else { LOGV("%s: mapped fd %d at offset %d, size %d", pmemdev, fd, offset, size); memset((char*)base + offset, 0, size); + //cacheflush(intptr_t(base) + offset, intptr_t(base) + offset + size, 0); *pBase = base; *pOffset = offset; *pFd = fd;