libgralloc-qsd8k: Initial gralloc commit

Update the gralloc HAL to match commit:

        commit 4d3c9ca6fabf2b0111ef6b567df7d244e124b9c2
        Author: Arun Kumar K.R <akkr@codeaurora.org>
        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
This commit is contained in:
Naomi Luis 2011-03-07 17:31:51 -08:00 committed by Govind Surti
parent df13c41d1f
commit a709f0300c
9 changed files with 830 additions and 67 deletions

View File

@ -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)

View File

@ -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 <sys/ioctl.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
@ -41,12 +43,45 @@
#include "gralloc_priv.h"
#include "gr.h"
#ifdef NO_SURFACEFLINGER_SWAPINTERVAL
#include <cutils/properties.h>
#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 (a<b) ? a : b;
}
/** max of int a, b */
static inline int max(int a, int b) {
return (a>b) ? 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<private_module_t*>(
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<private_module_t*>(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<private_handle_t const*>
(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<private_module_t*>(
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<private_module_t*>(
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<private_module_t*>(
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<private_module_t*>(
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<private_module_t*>(
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<private_module_t*>(
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<private_handle_t const*>(buffer);
private_module_t* m = reinterpret_cast<private_module_t*>(
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<private_module_t*>(
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<float&>(dev->device.xdpi) = m->xdpi;
const_cast<float&>(dev->device.ydpi) = m->ydpi;
const_cast<float&>(dev->device.fps) = m->fps;
const_cast<int&>(dev->device.minSwapInterval) = 1;
const_cast<int&>(dev->device.maxSwapInterval) = 1;
const_cast<int&>(dev->device.minSwapInterval) = private_module_t::PRIV_MIN_SWAP_INTERVAL;
const_cast<int&>(dev->device.maxSwapInterval) = private_module_t::PRIV_MAX_SWAP_INTERVAL;
if (m->finfo.reserved[0] == 0x5444 &&
m->finfo.reserved[1] == 0x5055) {

View File

@ -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<private_module_t*>(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;

View File

@ -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

View File

@ -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 {

View File

@ -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, &region);
err = ioctl(fd, PMEM_GET_TOTAL_SIZE, &region);
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;
}

143
libgralloc-qsd8k/gralloc_priv.h Normal file → Executable file
View File

@ -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 <linux/fb.h>
#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 <class T>
struct Node
{
T data;
Node<T> *next;
};
template <class T>
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<T>; //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<T>;
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<T> *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<T> *front;
Node<T> *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<struct qbuf_t> 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 {

151
libgralloc-qsd8k/mapper.cpp Normal file → Executable file
View File

@ -25,9 +25,11 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/ashmem.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <cutils/ashmem.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
@ -35,7 +37,7 @@
#include <linux/android_pmem.h>
#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, &region);
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;
}

View File

@ -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;