eclair snapshot

This commit is contained in:
Jean-Baptiste Queru 2009-11-12 18:46:07 -08:00
parent 045d5f482f
commit 81cd37b750
13 changed files with 1900 additions and 2252 deletions

View File

@ -1,35 +0,0 @@
BUILD_LIBCAMERA:=
ifeq ($(BUILD_LIBCAMERA),true)
# When zero we link against libmmcamera; when 1, we dlopen libmmcamera.
DLOPEN_LIBMMCAMERA:=1
ifneq ($(BUILD_TINY_ANDROID),true)
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= QualcommCameraHardware.cpp
LOCAL_CFLAGS:= -DDLOPEN_LIBMMCAMERA=$(DLOPEN_LIBMMCAMERA)
LOCAL_C_INCLUDES+= \
vendor/qcom/proprietary/mm-camera/common \
vendor/qcom/proprietary/mm-camera/apps/appslib \
vendor/qcom/proprietary/mm-camera/jpeg \
vendor/qcom/proprietary/mm-camera/jpeg/inc
LOCAL_SHARED_LIBRARIES:= libutils libui liblog
ifneq ($(DLOPEN_LIBMMCAMERA),1)
LOCAL_SHARED_LIBRARIES+= libqcamera
else
LOCAL_SHARED_LIBRARIES+= libdl
endif
LOCAL_MODULE:= libcamera
include $(BUILD_SHARED_LIBRARY)
endif # BUILD_TINY_ANDROID
endif # BUILD_LIBCAMERA

File diff suppressed because it is too large Load Diff

View File

@ -1,241 +0,0 @@
/*
** Copyright 2008, Google Inc.
**
** 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 ANDROID_HARDWARE_QUALCOMM_CAMERA_HARDWARE_H
#define ANDROID_HARDWARE_QUALCOMM_CAMERA_HARDWARE_H
#include <ui/CameraHardwareInterface.h>
#include <utils/MemoryBase.h>
#include <utils/MemoryHeapBase.h>
#include <stdint.h>
extern "C" {
#include <linux/android_pmem.h>
#include <media/msm_camera.h>
#include <camera.h>
}
struct str_map {
const char *const desc;
int val;
};
namespace android {
class QualcommCameraHardware : public CameraHardwareInterface {
public:
virtual sp<IMemoryHeap> getPreviewHeap() const;
virtual sp<IMemoryHeap> getRawHeap() const;
virtual status_t dump(int fd, const Vector<String16>& args) const;
virtual status_t startPreview(preview_callback cb, void* user);
virtual void stopPreview();
virtual bool previewEnabled();
virtual status_t startRecording(recording_callback cb, void* user);
virtual void stopRecording();
virtual bool recordingEnabled();
virtual void releaseRecordingFrame(const sp<IMemory>& mem);
virtual status_t autoFocus(autofocus_callback, void *user);
virtual status_t takePicture(shutter_callback, raw_callback,
jpeg_callback, void *);
virtual status_t cancelPicture(bool cancel_shutter,
bool cancel_raw, bool cancel_jpeg);
virtual status_t setParameters(const CameraParameters& params);
virtual CameraParameters getParameters() const;
virtual void release();
static sp<CameraHardwareInterface> createInstance();
static sp<QualcommCameraHardware> getInstance();
void receivePreviewFrame(struct msm_frame *frame);
void receiveJpegPicture(void);
void jpeg_set_location();
void receiveJpegPictureFragment(uint8_t *buf, uint32_t size);
void notifyShutter();
private:
QualcommCameraHardware();
virtual ~QualcommCameraHardware();
status_t startPreviewInternal();
void stopPreviewInternal();
friend void *auto_focus_thread(void *user);
void runAutoFocus();
void cancelAutoFocus();
bool native_set_dimension (int camfd);
bool native_jpeg_encode (void);
bool native_set_parm(cam_ctrl_type type, uint16_t length, void *value);
bool native_set_dimension(cam_ctrl_dimension_t *value);
int getParm(const char *parm_str, const str_map *parm_map);
static wp<QualcommCameraHardware> singleton;
/* These constants reflect the number of buffers that libmmcamera requires
for preview and raw, and need to be updated when libmmcamera
changes.
*/
static const int kPreviewBufferCount = 4;
static const int kRawBufferCount = 1;
static const int kJpegBufferCount = 1;
//TODO: put the picture dimensions in the CameraParameters object;
CameraParameters mParameters;
int mPreviewHeight;
int mPreviewWidth;
int mRawHeight;
int mRawWidth;
unsigned int frame_size;
bool mCameraRunning;
bool mPreviewInitialized;
// This class represents a heap which maintains several contiguous
// buffers. The heap may be backed by pmem (when pmem_pool contains
// the name of a /dev/pmem* file), or by ashmem (when pmem_pool == NULL).
struct MemPool : public RefBase {
MemPool(int buffer_size, int num_buffers,
int frame_size,
int frame_offset,
const char *name);
virtual ~MemPool() = 0;
void completeInitialization();
bool initialized() const {
return mHeap != NULL && mHeap->base() != MAP_FAILED;
}
virtual status_t dump(int fd, const Vector<String16>& args) const;
int mBufferSize;
int mNumBuffers;
int mFrameSize;
int mFrameOffset;
sp<MemoryHeapBase> mHeap;
sp<MemoryBase> *mBuffers;
const char *mName;
};
struct AshmemPool : public MemPool {
AshmemPool(int buffer_size, int num_buffers,
int frame_size,
int frame_offset,
const char *name);
};
struct PmemPool : public MemPool {
PmemPool(const char *pmem_pool,
int control_camera_fd, int pmem_type,
int buffer_size, int num_buffers,
int frame_size, int frame_offset,
const char *name);
virtual ~PmemPool();
int mFd;
int mPmemType;
int mCameraControlFd;
uint32_t mAlignedSize;
struct pmem_region mSize;
};
sp<PmemPool> mPreviewHeap;
sp<PmemPool> mThumbnailHeap;
sp<PmemPool> mRawHeap;
sp<AshmemPool> mJpegHeap;
void startCamera();
bool initPreview();
void deinitPreview();
bool initRaw(bool initJpegHeap);
void deinitRaw();
bool mFrameThreadRunning;
Mutex mFrameThreadWaitLock;
Condition mFrameThreadWait;
friend void *frame_thread(void *user);
void runFrameThread(void *data);
bool mShutterPending;
Mutex mShutterLock;
bool mSnapshotThreadRunning;
Mutex mSnapshotThreadWaitLock;
Condition mSnapshotThreadWait;
friend void *snapshot_thread(void *user);
void runSnapshotThread(void *data);
void initDefaultParameters();
void setAntibanding();
void setEffect();
void setWhiteBalance();
Mutex mLock;
bool mReleasedRecordingFrame;
void receiveRawPicture(void);
Mutex mCallbackLock;
Mutex mRecordLock;
Mutex mRecordFrameLock;
Condition mRecordWait;
Condition mStateWait;
/* mJpegSize keeps track of the size of the accumulated JPEG. We clear it
when we are about to take a picture, so at any time it contains either
zero, or the size of the last JPEG picture taken.
*/
uint32_t mJpegSize;
shutter_callback mShutterCallback;
raw_callback mRawPictureCallback;
jpeg_callback mJpegPictureCallback;
void *mPictureCallbackCookie;
autofocus_callback mAutoFocusCallback;
void *mAutoFocusCallbackCookie;
preview_callback mPreviewCallback;
void *mPreviewCallbackCookie;
recording_callback mRecordingCallback;
void *mRecordingCallbackCookie;
unsigned int mPreviewFrameSize;
int mRawSize;
int mJpegMaxSize;
#if DLOPEN_LIBMMCAMERA
void *libmmcamera;
#endif
int mCameraControlFd;
cam_ctrl_dimension_t mDimension;
bool mAutoFocusThreadRunning;
Mutex mAutoFocusThreadLock;
int mAutoFocusFd;
pthread_t mCamConfigThread;
pthread_t mFrameThread;
pthread_t mSnapshotThread;
common_crop_t mCrop;
struct msm_frame frames[kPreviewBufferCount];
bool mInPreviewCallback;
};
}; // namespace android
#endif

View File

@ -16,10 +16,27 @@
LOCAL_PATH:= $(call my-dir)
# HAL module implemenation, not prelinked and stored in
# hw/<COPYPIX_HARDWARE_MODULE_ID>.<ro.board.platform>.so
ifeq ($(TARGET_BOARD_PLATFORM),msm7k)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := copybit.c
LOCAL_SRC_FILES := copybit.cpp
LOCAL_MODULE := copybit.msm7k
LOCAL_C_INCLUDES += hardware/msm7k/libgralloc
LOCAL_CFLAGS += -DCOPYBIT_MSM7K=1
include $(BUILD_SHARED_LIBRARY)
endif
ifeq ($(TARGET_BOARD_PLATFORM),qsd8k)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := copybit.cpp
LOCAL_MODULE := copybit.qsd8k
LOCAL_C_INCLUDES += hardware/libhardware/modules/gralloc
LOCAL_CFLAGS += -DCOPYBIT_QSD8K=1
include $(BUILD_SHARED_LIBRARY)
endif

View File

@ -34,6 +34,20 @@
#include <hardware/copybit.h>
#include "gralloc_priv.h"
#define DEBUG_MDP_ERRORS 1
/******************************************************************************/
#if defined(COPYBIT_MSM7K)
#define MAX_SCALE_FACTOR (4)
#elif defined(COPYBIT_QSD8K)
#define MAX_SCALE_FACTOR (8)
#else
#error "Unsupported MDP version"
#endif
/******************************************************************************/
/** State information for each device instance */
@ -52,21 +66,21 @@ static int open_copybit(const struct hw_module_t* module, const char* name,
struct hw_device_t** device);
static struct hw_module_methods_t copybit_module_methods = {
.open = open_copybit
open: open_copybit
};
/*
* The COPYBIT Module
*/
const struct copybit_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = COPYBIT_HARDWARE_MODULE_ID,
.name = "QCT MSM7K COPYBIT Module",
.author = "Google, Inc.",
.methods = &copybit_module_methods,
struct copybit_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: COPYBIT_HARDWARE_MODULE_ID,
name: "QCT MSM7K COPYBIT Module",
author: "Google, Inc.",
methods: &copybit_module_methods
}
};
@ -103,9 +117,11 @@ static void intersect(struct copybit_rect_t *out,
/** convert COPYBIT_FORMAT to MDP format */
static int get_format(int format) {
switch (format) {
case COPYBIT_FORMAT_RGB_565: return MDP_RGB_565;
case COPYBIT_FORMAT_RGBX_8888: return MDP_RGBX_8888;
case COPYBIT_FORMAT_RGB_888: return MDP_RGB_888;
case COPYBIT_FORMAT_RGBA_8888: return MDP_RGBA_8888;
case COPYBIT_FORMAT_BGRA_8888: return MDP_BGRA_8888;
case COPYBIT_FORMAT_RGB_565: return MDP_RGB_565;
case COPYBIT_FORMAT_YCbCr_422_SP: return MDP_Y_CBCR_H2V1;
case COPYBIT_FORMAT_YCbCr_420_SP: return MDP_Y_CBCR_H2V2;
}
@ -113,15 +129,27 @@ static int get_format(int format) {
}
/** convert from copybit image to mdp image structure */
static void set_image(struct mdp_img *img,
const struct copybit_image_t *rhs) {
static void set_image(struct mdp_img *img, const struct copybit_image_t *rhs)
{
private_handle_t* hnd = (private_handle_t*)rhs->handle;
img->width = rhs->w;
img->height = rhs->h;
img->format = get_format(rhs->format);
img->offset = rhs->offset;
img->memory_id = rhs->fd;
img->offset = hnd->offset;
#if defined(COPYBIT_MSM7K)
if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_GPU) {
img->memory_id = hnd->gpu_fd;
if (img->format == MDP_RGBA_8888) {
// msm7201A GPU only supports BGRA_8888 destinations
img->format = MDP_BGRA_8888;
}
} else {
img->memory_id = hnd->fd;
}
#else
img->memory_id = hnd->fd;
#endif
}
/** setup rectangles */
static void set_rects(struct copybit_context_t *dev,
struct mdp_blit_req *e,
@ -166,7 +194,7 @@ static void set_rects(struct copybit_context_t *dev,
static void set_infos(struct copybit_context_t *dev, struct mdp_blit_req *req) {
req->alpha = dev->mAlpha;
req->transp_mask = MDP_TRANSP_NOP;
req->flags = dev->mFlags;
req->flags = dev->mFlags | MDP_BLEND_FG_PREMULT;
}
/** copy the bits */
@ -175,10 +203,37 @@ static int msm_copybit(struct copybit_context_t *dev, void const *list)
int err = ioctl(dev->mFD, MSMFB_BLIT,
(struct mdp_blit_req_list const*)list);
LOGE_IF(err<0, "copyBits failed (%s)", strerror(errno));
if (err == 0)
if (err == 0) {
return 0;
else
} else {
#if DEBUG_MDP_ERRORS
struct mdp_blit_req_list const* l = (struct mdp_blit_req_list const*)list;
for (int i=0 ; i<l->count ; i++) {
LOGD("%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"
,
i,
l->req[i].src.width,
l->req[i].src.height,
l->req[i].src.format,
l->req[i].src_rect.x,
l->req[i].src_rect.y,
l->req[i].src_rect.w,
l->req[i].src_rect.h,
l->req[i].dst.width,
l->req[i].dst.height,
l->req[i].dst.format,
l->req[i].dst_rect.x,
l->req[i].dst_rect.y,
l->req[i].dst_rect.w,
l->req[i].dst_rect.h,
l->req[i].flags
);
}
#endif
return -errno;
}
}
/*****************************************************************************/
@ -257,10 +312,10 @@ static int get(struct copybit_device_t *dev, int name)
if (ctx) {
switch(name) {
case COPYBIT_MINIFICATION_LIMIT:
value = 4;
value = MAX_SCALE_FACTOR;
break;
case COPYBIT_MAGNIFICATION_LIMIT:
value = 4;
value = MAX_SCALE_FACTOR;
break;
case COPYBIT_SCALING_FRAC_BITS:
value = 32;
@ -304,7 +359,13 @@ static int stretch_copybit(
return -EINVAL;
}
}
if (src_rect->l < 0 || src_rect->r > src->w ||
src_rect->t < 0 || src_rect->b > src->h) {
// this is always invalid
return -EINVAL;
}
const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]);
const struct copybit_rect_t bounds = { 0, 0, dst->w, dst->h };
struct copybit_rect_t clip;
@ -312,10 +373,18 @@ static int stretch_copybit(
status = 0;
while ((status == 0) && region->next(region, &clip)) {
intersect(&clip, &bounds, &clip);
set_infos(ctx, &list.req[list.count]);
set_image(&list.req[list.count].dst, dst);
set_image(&list.req[list.count].src, src);
set_rects(ctx, &list.req[list.count], dst_rect, src_rect, &clip);
mdp_blit_req* req = &list.req[list.count];
set_infos(ctx, req);
set_image(&req->dst, dst);
set_image(&req->src, src);
set_rects(ctx, req, dst_rect, src_rect, &clip);
if (req->src_rect.w<=0 || req->src_rect.h<=0)
continue;
if (req->dst_rect.w<=0 || req->dst_rect.h<=0)
continue;
if (++list.count == maxCount) {
status = msm_copybit(ctx, &list);
list.count = 0;
@ -360,12 +429,13 @@ static int open_copybit(const struct hw_module_t* module, const char* name,
struct hw_device_t** device)
{
int status = -EINVAL;
struct copybit_context_t *ctx = malloc(sizeof(struct copybit_context_t));
copybit_context_t *ctx;
ctx = (copybit_context_t *)malloc(sizeof(copybit_context_t));
memset(ctx, 0, sizeof(*ctx));
ctx->device.common.tag = HARDWARE_DEVICE_TAG;
ctx->device.common.version = 0;
ctx->device.common.module = module;
ctx->device.common.version = 1;
ctx->device.common.module = const_cast<hw_module_t*>(module);
ctx->device.common.close = close_copybit;
ctx->device.set_parameter = set_parameter_copybit;
ctx->device.get = get;

View File

@ -0,0 +1,32 @@
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
# HAL module implemenation, not prelinked and stored in
# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libcutils libGLESv1_CM
LOCAL_SRC_FILES := \
allocator.cpp \
gralloc.cpp \
framebuffer.cpp \
mapper.cpp
LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM)
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\"
include $(BUILD_SHARED_LIBRARY)

View File

@ -0,0 +1,170 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cutils/log.h>
#include "allocator.h"
// align all the memory blocks on a cache-line boundary
const int SimpleBestFitAllocator::kMemoryAlign = 32;
SimpleBestFitAllocator::SimpleBestFitAllocator()
: mHeapSize(0)
{
}
SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
: mHeapSize(0)
{
setSize(size);
}
SimpleBestFitAllocator::~SimpleBestFitAllocator()
{
while(!mList.isEmpty()) {
delete mList.remove(mList.head());
}
}
ssize_t SimpleBestFitAllocator::setSize(size_t size)
{
Locker::Autolock _l(mLock);
if (mHeapSize != 0) return -EINVAL;
size_t pagesize = getpagesize();
mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
mList.insertHead(node);
return size;
}
size_t SimpleBestFitAllocator::size() const
{
return mHeapSize;
}
ssize_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
{
Locker::Autolock _l(mLock);
if (mHeapSize == 0) return -EINVAL;
ssize_t offset = alloc(size, flags);
return offset;
}
ssize_t SimpleBestFitAllocator::deallocate(size_t offset)
{
Locker::Autolock _l(mLock);
if (mHeapSize == 0) return -EINVAL;
chunk_t const * const freed = dealloc(offset);
if (freed) {
return 0;
}
return -ENOENT;
}
ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
{
if (size == 0) {
return 0;
}
size = (size + kMemoryAlign-1) / kMemoryAlign;
chunk_t* free_chunk = 0;
chunk_t* cur = mList.head();
size_t pagesize = getpagesize();
while (cur) {
int extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
// best fit
if (cur->free && (cur->size >= (size+extra))) {
if ((!free_chunk) || (cur->size < free_chunk->size)) {
free_chunk = cur;
}
if (cur->size == size) {
break;
}
}
cur = cur->next;
}
if (free_chunk) {
const size_t free_size = free_chunk->size;
free_chunk->free = 0;
free_chunk->size = size;
if (free_size > size) {
int extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
if (extra) {
chunk_t* split = new chunk_t(free_chunk->start, extra);
free_chunk->start += extra;
mList.insertBefore(free_chunk, split);
}
LOGE_IF(((free_chunk->start*kMemoryAlign)&(pagesize-1)),
"page is not aligned!!!");
const ssize_t tail_free = free_size - (size+extra);
if (tail_free > 0) {
chunk_t* split = new chunk_t(
free_chunk->start + free_chunk->size, tail_free);
mList.insertAfter(free_chunk, split);
}
}
return (free_chunk->start)*kMemoryAlign;
}
return -ENOMEM;
}
SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
{
start = start / kMemoryAlign;
chunk_t* cur = mList.head();
while (cur) {
if (cur->start == start) {
LOG_FATAL_IF(cur->free,
"block at offset 0x%08lX of size 0x%08lX already freed",
cur->start*kMemoryAlign, cur->size*kMemoryAlign);
// merge freed blocks together
chunk_t* freed = cur;
cur->free = 1;
do {
chunk_t* const p = cur->prev;
chunk_t* const n = cur->next;
if (p && (p->free || !cur->size)) {
freed = p;
p->size += cur->size;
mList.remove(cur);
delete cur;
}
cur = n;
} while (cur && cur->free);
#ifndef NDEBUG
if (!freed->free) {
dump_l("dealloc (!freed->free)");
}
#endif
LOG_FATAL_IF(!freed->free,
"freed block at offset 0x%08lX of size 0x%08lX is not free!",
freed->start * kMemoryAlign, freed->size * kMemoryAlign);
return freed;
}
cur = cur->next;
}
return 0;
}

View File

@ -0,0 +1,129 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GRALLOC_ALLOCATOR_H_
#define GRALLOC_ALLOCATOR_H_
#include <stdint.h>
#include <sys/types.h>
#include "gr.h"
// ----------------------------------------------------------------------------
/*
* A simple templatized doubly linked-list implementation
*/
template <typename NODE>
class LinkedList
{
NODE* mFirst;
NODE* mLast;
public:
LinkedList() : mFirst(0), mLast(0) { }
bool isEmpty() const { return mFirst == 0; }
NODE const* head() const { return mFirst; }
NODE* head() { return mFirst; }
NODE const* tail() const { return mLast; }
NODE* tail() { return mLast; }
void insertAfter(NODE* node, NODE* newNode) {
newNode->prev = node;
newNode->next = node->next;
if (node->next == 0) mLast = newNode;
else node->next->prev = newNode;
node->next = newNode;
}
void insertBefore(NODE* node, NODE* newNode) {
newNode->prev = node->prev;
newNode->next = node;
if (node->prev == 0) mFirst = newNode;
else node->prev->next = newNode;
node->prev = newNode;
}
void insertHead(NODE* newNode) {
if (mFirst == 0) {
mFirst = mLast = newNode;
newNode->prev = newNode->next = 0;
} else {
newNode->prev = 0;
newNode->next = mFirst;
mFirst->prev = newNode;
mFirst = newNode;
}
}
void insertTail(NODE* newNode) {
if (mLast == 0) {
insertHead(newNode);
} else {
newNode->prev = mLast;
newNode->next = 0;
mLast->next = newNode;
mLast = newNode;
}
}
NODE* remove(NODE* node) {
if (node->prev == 0) mFirst = node->next;
else node->prev->next = node->next;
if (node->next == 0) mLast = node->prev;
else node->next->prev = node->prev;
return node;
}
};
class SimpleBestFitAllocator
{
public:
SimpleBestFitAllocator();
SimpleBestFitAllocator(size_t size);
~SimpleBestFitAllocator();
ssize_t setSize(size_t size);
ssize_t allocate(size_t size, uint32_t flags = 0);
ssize_t deallocate(size_t offset);
size_t size() const;
private:
struct chunk_t {
chunk_t(size_t start, size_t size)
: start(start), size(size), free(1), prev(0), next(0) {
}
size_t start;
size_t size : 28;
int free : 4;
mutable chunk_t* prev;
mutable chunk_t* next;
};
ssize_t alloc(size_t size, uint32_t flags);
chunk_t* dealloc(size_t start);
static const int kMemoryAlign;
mutable Locker mLock;
LinkedList<chunk_t> mList;
size_t mHeapSize;
};
#endif /* GRALLOC_ALLOCATOR_H_ */

View File

@ -0,0 +1,437 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/mman.h>
#include <dlfcn.h>
#include <cutils/ashmem.h>
#include <cutils/log.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdlib.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <linux/fb.h>
#include <linux/msm_mdp.h>
#include <GLES/gl.h>
#include "gralloc_priv.h"
#include "gr.h"
/*****************************************************************************/
// numbers of buffers for page flipping
#define NUM_BUFFERS 2
enum {
PAGE_FLIP = 0x00000001,
LOCKED = 0x00000002
};
struct fb_context_t {
framebuffer_device_t device;
};
/*****************************************************************************/
static void
msm_copy_buffer(buffer_handle_t handle, int fd, int width, int height,
int x, int y, int w, int h);
static int fb_setSwapInterval(struct framebuffer_device_t* dev,
int interval)
{
fb_context_t* ctx = (fb_context_t*)dev;
if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval)
return -EINVAL;
// FIXME: implement fb_setSwapInterval
return 0;
}
static int fb_setUpdateRect(struct framebuffer_device_t* dev,
int l, int t, int w, int h)
{
if (((w|h) <= 0) || ((l|t)<0))
return -EINVAL;
fb_context_t* ctx = (fb_context_t*)dev;
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
m->info.reserved[0] = 0x54445055; // "UPDT";
m->info.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
m->info.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
return 0;
}
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
if (private_handle_t::validate(buffer) < 0)
return -EINVAL;
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);
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;
}
m->currentBuffer = buffer;
} else {
// If we can't do the page_flip, just copy the buffer to the front
// FIXME: use copybit HAL instead of memcpy
void* fb_vaddr;
void* buffer_vaddr;
m->base.lock(&m->base, m->framebuffer,
GRALLOC_USAGE_SW_WRITE_RARELY,
0, 0, m->info.xres, m->info.yres,
&fb_vaddr);
m->base.lock(&m->base, buffer,
GRALLOC_USAGE_SW_READ_RARELY,
0, 0, m->info.xres, m->info.yres,
&buffer_vaddr);
//memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
msm_copy_buffer(m->framebuffer, m->framebuffer->fd,
m->info.xres, m->info.yres,
m->info.xoffset, m->info.yoffset,
m->info.width, m->info.height);
m->base.unlock(&m->base, buffer);
m->base.unlock(&m->base, m->framebuffer);
}
return 0;
}
static int fb_compositionComplete(struct framebuffer_device_t* dev)
{
// STOPSHIP: Properly implement composition complete callback
glFinish();
return 0;
}
/*****************************************************************************/
int mapFrameBufferLocked(struct private_module_t* module)
{
// already initialized...
if (module->framebuffer) {
return 0;
}
char const * const device_template[] = {
"/dev/graphics/fb%u",
"/dev/fb%u",
0 };
int fd = -1;
int i=0;
char name[64];
while ((fd==-1) && device_template[i]) {
snprintf(name, 64, device_template[i], 0);
fd = open(name, O_RDWR, 0);
i++;
}
if (fd < 0)
return -errno;
struct fb_fix_screeninfo finfo;
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;
struct fb_var_screeninfo info;
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;
info.reserved[0] = 0;
info.reserved[1] = 0;
info.reserved[2] = 0;
info.xoffset = 0;
info.yoffset = 0;
info.activate = FB_ACTIVATE_NOW;
/*
* 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;
/*
* Request NUM_BUFFERS screens (at lest 2 for page flipping)
*/
info.yres_virtual = info.yres * NUM_BUFFERS;
uint32_t flags = PAGE_FLIP;
if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
}
if (info.yres_virtual < info.yres * 2) {
// we need at least 2 for page-flipping
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
info.yres_virtual, info.yres*2);
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;
int refreshRate = 1000000000000000LLU /
(
uint64_t( info.upper_margin + info.lower_margin + info.yres )
* ( info.left_margin + info.right_margin + info.xres )
* info.pixclock
);
if (refreshRate == 0) {
// bleagh, bad info from the driver
refreshRate = 60*1000; // 60 Hz
}
if (int(info.width) <= 0 || int(info.height) <= 0) {
// the driver doesn't return that information
// default to 160 dpi
info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
}
float xdpi = (info.xres * 25.4f) / info.width;
float ydpi = (info.yres * 25.4f) / info.height;
float fps = refreshRate / 1000.0f;
LOGI( "using (fd=%d)\n"
"id = %s\n"
"xres = %d px\n"
"yres = %d px\n"
"xres_virtual = %d px\n"
"yres_virtual = %d px\n"
"bpp = %d\n"
"r = %2u:%u\n"
"g = %2u:%u\n"
"b = %2u:%u\n",
fd,
finfo.id,
info.xres,
info.yres,
info.xres_virtual,
info.yres_virtual,
info.bits_per_pixel,
info.red.offset, info.red.length,
info.green.offset, info.green.length,
info.blue.offset, info.blue.length
);
LOGI( "width = %d mm (%f dpi)\n"
"height = %d mm (%f dpi)\n"
"refresh rate = %.2f Hz\n",
info.width, xdpi,
info.height, ydpi,
fps
);
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;
if (finfo.smem_len <= 0)
return -errno;
module->flags = flags;
module->info = info;
module->finfo = finfo;
module->xdpi = xdpi;
module->ydpi = ydpi;
module->fps = fps;
/*
* map the framebuffer
*/
int err;
size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
module->framebuffer = new private_handle_t(dup(fd), fbSize,
private_handle_t::PRIV_FLAGS_USES_PMEM);
module->numBuffers = info.yres_virtual / info.yres;
module->bufferMask = 0;
void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (vaddr == MAP_FAILED) {
LOGE("Error mapping the framebuffer (%s)", strerror(errno));
return -errno;
}
module->framebuffer->base = intptr_t(vaddr);
module->framebuffer->phys = intptr_t(finfo.smem_start);
memset(vaddr, 0, fbSize);
return 0;
}
static int mapFrameBuffer(struct private_module_t* module)
{
pthread_mutex_lock(&module->lock);
int err = mapFrameBufferLocked(module);
pthread_mutex_unlock(&module->lock);
return err;
}
/*****************************************************************************/
static int fb_close(struct hw_device_t *dev)
{
fb_context_t* ctx = (fb_context_t*)dev;
if (ctx) {
free(ctx);
}
return 0;
}
int fb_device_open(hw_module_t const* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
alloc_device_t* gralloc_device;
status = gralloc_open(module, &gralloc_device);
if (status < 0)
return status;
/* initialize our state here */
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = fb_close;
dev->device.setSwapInterval = fb_setSwapInterval;
dev->device.post = fb_post;
dev->device.setUpdateRect = 0;
dev->device.compositionComplete = fb_compositionComplete;
private_module_t* m = (private_module_t*)module;
status = mapFrameBuffer(m);
if (status >= 0) {
int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
const_cast<uint32_t&>(dev->device.flags) = 0;
const_cast<uint32_t&>(dev->device.width) = m->info.xres;
const_cast<uint32_t&>(dev->device.height) = m->info.yres;
const_cast<int&>(dev->device.stride) = stride;
const_cast<int&>(dev->device.format) = HAL_PIXEL_FORMAT_RGB_565;
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;
if (m->finfo.reserved[0] == 0x5444 &&
m->finfo.reserved[1] == 0x5055) {
dev->device.setUpdateRect = fb_setUpdateRect;
LOGD("UPDATE_ON_DEMAND supported");
}
*device = &dev->device.common;
}
}
return status;
}
/* Copy a pmem buffer to the framebuffer */
static void
msm_copy_buffer(buffer_handle_t handle, int fd, int width, int height,
int x, int y, int w, int h)
{
struct {
unsigned int count;
mdp_blit_req req;
} blit;
private_handle_t *priv = (private_handle_t*) handle;
memset(&blit, 0, sizeof(blit));
blit.count = 1;
blit.req.flags = 0;
blit.req.alpha = 0xff;
blit.req.transp_mask = 0xffffffff;
blit.req.src.width = width;
blit.req.src.height = height;
blit.req.src.offset = 0;
blit.req.src.memory_id = priv->fd;
blit.req.dst.width = width;
blit.req.dst.height = height;
blit.req.dst.offset = 0;
blit.req.dst.memory_id = fd;
blit.req.dst.format = MDP_RGB_565;
blit.req.src_rect.x = blit.req.dst_rect.x = x;
blit.req.src_rect.y = blit.req.dst_rect.y = y;
blit.req.src_rect.w = blit.req.dst_rect.w = w;
blit.req.src_rect.h = blit.req.dst_rect.h = h;
if (ioctl(fd, MSMFB_BLIT, &blit))
LOGE("MSMFB_BLIT failed = %d", -errno);
}

63
libgralloc-qsd8k/gr.h Normal file
View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GR_H_
#define GR_H_
#include <stdint.h>
#ifdef HAVE_ANDROID_OS // just want PAGE_SIZE define
# include <asm/page.h>
#else
# include <sys/user.h>
#endif
#include <limits.h>
#include <sys/cdefs.h>
#include <hardware/gralloc.h>
#include <pthread.h>
#include <errno.h>
#include <cutils/native_handle.h>
/*****************************************************************************/
struct private_module_t;
struct private_handle_t;
inline size_t roundUpToPageSize(size_t x) {
return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
}
int mapFrameBufferLocked(struct private_module_t* module);
int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd);
/*****************************************************************************/
class Locker {
pthread_mutex_t mutex;
public:
class Autolock {
Locker& locker;
public:
inline Autolock(Locker& locker) : locker(locker) { locker.lock(); }
inline ~Autolock() { locker.unlock(); }
};
inline Locker() { pthread_mutex_init(&mutex, 0); }
inline ~Locker() { pthread_mutex_destroy(&mutex); }
inline void lock() { pthread_mutex_lock(&mutex); }
inline void unlock() { pthread_mutex_unlock(&mutex); }
};
#endif /* GR_H_ */

View File

@ -0,0 +1,490 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <cutils/ashmem.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include "gralloc_priv.h"
#include "allocator.h"
#if HAVE_ANDROID_OS
#include <linux/android_pmem.h>
#endif
/*****************************************************************************/
static SimpleBestFitAllocator sAllocator;
/*****************************************************************************/
struct gralloc_context_t {
alloc_device_t device;
/* our private data here */
};
static int gralloc_alloc_buffer(alloc_device_t* dev,
size_t size, int usage, buffer_handle_t* pHandle);
/*****************************************************************************/
int fb_device_open(const hw_module_t* module, const char* name,
hw_device_t** device);
static int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device);
extern int gralloc_lock(gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr);
extern int gralloc_unlock(gralloc_module_t const* module,
buffer_handle_t handle);
extern int gralloc_register_buffer(gralloc_module_t const* module,
buffer_handle_t handle);
extern int gralloc_unregister_buffer(gralloc_module_t const* module,
buffer_handle_t handle);
extern int gralloc_perform(struct gralloc_module_t const* module,
int operation, ... );
/*****************************************************************************/
static struct hw_module_methods_t gralloc_module_methods = {
open: gralloc_device_open
};
struct private_module_t HAL_MODULE_INFO_SYM = {
base: {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: GRALLOC_HARDWARE_MODULE_ID,
name: "Graphics Memory Allocator Module",
author: "The Android Open Source Project",
methods: &gralloc_module_methods
},
registerBuffer: gralloc_register_buffer,
unregisterBuffer: gralloc_unregister_buffer,
lock: gralloc_lock,
unlock: gralloc_unlock,
perform: gralloc_perform,
},
framebuffer: 0,
flags: 0,
numBuffers: 0,
bufferMask: 0,
lock: PTHREAD_MUTEX_INITIALIZER,
currentBuffer: 0,
pmem_master: -1,
pmem_master_base: 0,
master_phys: 0
};
/*****************************************************************************/
static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev,
size_t size, int usage, buffer_handle_t* pHandle)
{
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
// allocate the framebuffer
if (m->framebuffer == NULL) {
// initialize the framebuffer, the framebuffer is mapped once
// and forever.
int err = mapFrameBufferLocked(m);
if (err < 0) {
return err;
}
}
const uint32_t bufferMask = m->bufferMask;
const uint32_t numBuffers = m->numBuffers;
const size_t bufferSize = m->finfo.line_length * m->info.yres;
if (numBuffers == 1) {
// If we have only one buffer, we never use page-flipping. Instead,
// we return a regular buffer which will be memcpy'ed to the main
// screen when post is called.
int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
return gralloc_alloc_buffer(dev, bufferSize, newUsage, pHandle);
}
if (bufferMask >= ((1LU<<numBuffers)-1)) {
// We ran out of buffers.
return -ENOMEM;
}
// 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::PRIV_FLAGS_USES_PMEM |
private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
// find a free slot
for (uint32_t i=0 ; i<numBuffers ; i++) {
if ((bufferMask & (1LU<<i)) == 0) {
m->bufferMask |= (1LU<<i);
break;
}
vaddr += bufferSize;
}
hnd->base = vaddr;
hnd->offset = vaddr - intptr_t(m->framebuffer->base);
hnd->phys = intptr_t(m->framebuffer->phys) + hnd->offset;
*pHandle = hnd;
return 0;
}
static int gralloc_alloc_framebuffer(alloc_device_t* dev,
size_t size, int usage, buffer_handle_t* pHandle)
{
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
pthread_mutex_lock(&m->lock);
int err = gralloc_alloc_framebuffer_locked(dev, size, usage, pHandle);
pthread_mutex_unlock(&m->lock);
return err;
}
static int init_pmem_area_locked(private_module_t* m)
{
int err = 0;
int master_fd = open("/dev/pmem", O_RDWR, 0);
if (master_fd >= 0) {
size_t size;
pmem_region region;
if (ioctl(master_fd, PMEM_GET_TOTAL_SIZE, &region) < 0) {
LOGE("PMEM_GET_TOTAL_SIZE failed, limp mode");
size = 8<<20; // 8 MiB
} else {
size = region.len;
}
sAllocator.setSize(size);
void* base = mmap(0, size,
PROT_READ|PROT_WRITE, MAP_SHARED, master_fd, 0);
if (base == MAP_FAILED) {
err = -errno;
base = 0;
close(master_fd);
master_fd = -1;
} else {
// FIXME: get physical address, eventually this will have to go away
pmem_region region;
err = ioctl(master_fd, PMEM_GET_PHYS, &region);
if (err < 0) {
LOGE("PMEM_GET_PHYS failed (%s)", strerror(-errno));
} else {
m->master_phys = (unsigned long)region.offset;
}
}
m->pmem_master = master_fd;
m->pmem_master_base = base;
} else {
err = -errno;
}
return err;
}
static int init_pmem_area(private_module_t* m)
{
pthread_mutex_lock(&m->lock);
int err = m->pmem_master;
if (err == -1) {
// first time, try to initialize pmem
err = init_pmem_area_locked(m);
if (err) {
m->pmem_master = err;
}
} else if (err < 0) {
// pmem couldn't be initialized, never use it
} else {
// pmem OK
err = 0;
}
pthread_mutex_unlock(&m->lock);
return err;
}
static int gralloc_alloc_buffer(alloc_device_t* dev,
size_t size, int usage, buffer_handle_t* pHandle)
{
int err = 0;
int flags = 0;
int fd = -1;
void* base = 0;
int offset = 0;
int lockState = 0;
size = roundUpToPageSize(size);
if (usage & GRALLOC_USAGE_HW_TEXTURE) {
// enable pmem in that case, so our software GL can fallback to
// the copybit module.
flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
}
if (usage & GRALLOC_USAGE_HW_2D) {
flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
}
if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) == 0) {
try_ashmem:
fd = ashmem_create_region("gralloc-buffer", size);
if (fd < 0) {
LOGE("couldn't create ashmem (%s)", strerror(errno));
err = -errno;
}
} else {
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
err = init_pmem_area(m);
if (err == 0) {
// PMEM buffers are always mmapped
base = m->pmem_master_base;
lockState |= private_handle_t::LOCK_STATE_MAPPED;
offset = sAllocator.allocate(size);
if (offset < 0) {
// no more pmem memory
err = -ENOMEM;
} else {
struct pmem_region sub = { offset, size };
// now create the "sub-heap"
fd = open("/dev/pmem", O_RDWR, 0);
err = fd < 0 ? fd : 0;
// and connect to it
if (err == 0)
err = ioctl(fd, PMEM_CONNECT, m->pmem_master);
// and make it available to the client process
if (err == 0)
err = ioctl(fd, PMEM_MAP, &sub);
if (err < 0) {
err = -errno;
close(fd);
sAllocator.deallocate(offset);
fd = -1;
}
memset((char*)base + offset, 0, size);
//LOGD_IF(!err, "allocating pmem size=%d, offset=%d", size, offset);
}
} else {
if ((usage & GRALLOC_USAGE_HW_2D) == 0) {
// the caller didn't request PMEM, so we can try something else
flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM;
err = 0;
goto try_ashmem;
} else {
LOGE("couldn't open pmem (%s)", strerror(errno));
}
}
}
if (err == 0) {
private_handle_t* hnd = new private_handle_t(fd, size, flags);
hnd->offset = offset;
hnd->base = int(base)+offset;
hnd->lockState = lockState;
if (flags & private_handle_t::PRIV_FLAGS_USES_PMEM) {
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
hnd->phys = m->master_phys + offset;
}
*pHandle = hnd;
}
LOGE_IF(err, "gralloc failed err=%s", strerror(-err));
return err;
}
/*****************************************************************************/
static int gralloc_alloc(alloc_device_t* dev,
int w, int h, int format, int usage,
buffer_handle_t* pHandle, int* pStride)
{
if (!pHandle || !pStride)
return -EINVAL;
size_t size, alignedw, alignedh;
if (format == HAL_PIXEL_FORMAT_YCbCr_420_SP ||
format == HAL_PIXEL_FORMAT_YCbCr_422_SP)
{
// FIXME: there is no way to return the alignedh
alignedw = (w + 1) & ~1;
switch (format) {
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
size = alignedw * h * 2;
break;
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
alignedh = (h+1) & ~1;
size = (alignedw * alignedh) + (w/2 * h/2) * 2;
break;
default:
return -EINVAL;
}
} else {
alignedw = (w + 31) & ~31;
alignedh = (h + 31) & ~31;
int bpp = 0;
switch (format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_BGRA_8888:
bpp = 4;
break;
case HAL_PIXEL_FORMAT_RGB_888:
bpp = 3;
break;
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_RGBA_5551:
case HAL_PIXEL_FORMAT_RGBA_4444:
bpp = 2;
break;
default:
return -EINVAL;
}
size = alignedw * alignedh * bpp;
}
int err;
if (usage & GRALLOC_USAGE_HW_FB) {
err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);
} else {
err = gralloc_alloc_buffer(dev, size, usage, pHandle);
}
if (err < 0) {
return err;
}
*pStride = alignedw;
return 0;
}
static int gralloc_free(alloc_device_t* dev,
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle);
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
// free this buffer
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
const size_t bufferSize = m->finfo.line_length * m->info.yres;
int index = (hnd->base - m->framebuffer->base) / bufferSize;
m->bufferMask &= ~(1<<index);
} else {
if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) {
if (hnd->fd >= 0) {
struct pmem_region sub = { hnd->offset, hnd->size };
int err = ioctl(hnd->fd, PMEM_UNMAP, &sub);
LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
"fd=%d, sub.offset=%lu, sub.size=%lu",
strerror(errno), hnd->fd, hnd->offset, hnd->size);
if (err == 0) {
// we can't deallocate the memory in case of UNMAP failure
// because it would give that process access to someone else's
// surfaces, which would be a security breach.
sAllocator.deallocate(hnd->offset);
}
}
}
gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>(
dev->common.module);
terminateBuffer(module, const_cast<private_handle_t*>(hnd));
}
close(hnd->fd);
delete hnd;
return 0;
}
/*****************************************************************************/
static int gralloc_close(struct hw_device_t *dev)
{
gralloc_context_t* ctx = reinterpret_cast<gralloc_context_t*>(dev);
if (ctx) {
/* TODO: keep a list of all buffer_handle_t created, and free them
* all here.
*/
free(ctx);
}
return 0;
}
int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
gralloc_context_t *dev;
dev = (gralloc_context_t*)malloc(sizeof(*dev));
/* initialize our state here */
memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = gralloc_close;
dev->device.alloc = gralloc_alloc;
dev->device.free = gralloc_free;
*device = &dev->device.common;
status = 0;
} else {
status = fb_device_open(module, name, device);
}
return status;
}

View File

@ -0,0 +1,140 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GRALLOC_PRIV_H_
#define GRALLOC_PRIV_H_
#include <stdint.h>
#include <limits.h>
#include <sys/cdefs.h>
#include <hardware/gralloc.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <cutils/native_handle.h>
#include <linux/fb.h>
/*****************************************************************************/
struct private_module_t;
struct private_handle_t;
struct private_module_t {
gralloc_module_t base;
struct private_handle_t* framebuffer;
uint32_t flags;
uint32_t numBuffers;
uint32_t bufferMask;
pthread_mutex_t lock;
buffer_handle_t currentBuffer;
int pmem_master;
void* pmem_master_base;
unsigned long master_phys;
struct fb_var_screeninfo info;
struct fb_fix_screeninfo finfo;
float xdpi;
float ydpi;
float fps;
enum {
// flag to indicate we'll post this buffer
PRIV_USAGE_LOCKED_FOR_POST = 0x80000000
};
};
/*****************************************************************************/
#ifdef __cplusplus
struct private_handle_t : public native_handle {
#else
struct private_handle_t {
native_handle_t nativeHandle;
#endif
enum {
PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
PRIV_FLAGS_USES_PMEM = 0x00000002,
};
enum {
LOCK_STATE_WRITE = 1<<31,
LOCK_STATE_MAPPED = 1<<30,
LOCK_STATE_READ_MASK = 0x3FFFFFFF
};
// file-descriptors
int fd;
// ints
int magic;
int flags;
int size;
int offset;
int gpu_fd; // stored as an int, b/c we don't want it marshalled
// FIXME: the attributes below should be out-of-line
int base;
int lockState;
int writeOwner;
int phys; // The physical address of that chunk of memory. If using ashmem, set to 0 They don't care
int pid;
#ifdef __cplusplus
static const int sNumInts = 10;
static const int sNumFds = 1;
static const int sMagic = 'gmsm';
private_handle_t(int fd, int size, int flags) :
fd(fd), magic(sMagic), flags(flags), size(size), offset(0), gpu_fd(-1),
base(0), lockState(0), writeOwner(0), phys(0), pid(getpid())
{
version = sizeof(native_handle);
numInts = sNumInts;
numFds = sNumFds;
}
~private_handle_t() {
magic = 0;
}
bool usesPhysicallyContiguousMemory() {
return (flags & PRIV_FLAGS_USES_PMEM) != 0;
}
static int validate(const native_handle* h) {
const private_handle_t* hnd = (const private_handle_t*)h;
if (!h || h->version != sizeof(native_handle) ||
h->numInts != sNumInts || h->numFds != sNumFds ||
hnd->magic != sMagic)
{
LOGE("invalid gralloc handle (at %p)", h);
return -EINVAL;
}
return 0;
}
static private_handle_t* dynamicCast(const native_handle* in) {
if (validate(in) == 0) {
return (private_handle_t*) in;
}
return NULL;
}
#endif
};
#endif /* GRALLOC_PRIV_H_ */

322
libgralloc-qsd8k/mapper.cpp Normal file
View File

@ -0,0 +1,322 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <limits.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include "gralloc_priv.h"
// we need this for now because pmem cannot mmap at an offset
#define PMEM_HACK 1
/* desktop Linux needs a little help with gettid() */
#if defined(ARCH_X86) && !defined(HAVE_ANDROID_OS)
#define __KERNEL__
# include <linux/unistd.h>
pid_t gettid() { return syscall(__NR_gettid);}
#undef __KERNEL__
#endif
/*****************************************************************************/
static int gralloc_map(gralloc_module_t const* module,
buffer_handle_t handle,
void** vaddr)
{
private_handle_t* hnd = (private_handle_t*)handle;
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,
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));
hnd->base = 0;
return -errno;
}
hnd->base = intptr_t(mappedAddress) + hnd->offset;
//LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
// hnd->fd, hnd->offset, hnd->size, mappedAddress);
}
*vaddr = (void*)hnd->base;
return 0;
}
static int gralloc_unmap(gralloc_module_t const* module,
buffer_handle_t handle)
{
private_handle_t* hnd = (private_handle_t*)handle;
if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
void* base = (void*)hnd->base;
size_t size = hnd->size;
#if PMEM_HACK
base = (void*)(intptr_t(base) - hnd->offset);
size += hnd->offset;
#endif
//LOGD("unmapping from %p, size=%d", base, size);
if (munmap(base, size) < 0) {
LOGE("Could not unmap %s", strerror(errno));
}
}
hnd->base = 0;
return 0;
}
/*****************************************************************************/
static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER;
/*****************************************************************************/
int gralloc_register_buffer(gralloc_module_t const* module,
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
// In this implementation, we don't need to do anything here
/* NOTE: we need to initialize the buffer as not mapped/not locked
* because it shouldn't when this function is called the first time
* in a new process. Ideally these flags shouldn't be part of the
* handle, but instead maintained in the kernel or at least
* out-of-line
*/
// if this handle was created in this process, then we keep it as is.
private_handle_t* hnd = (private_handle_t*)handle;
if (hnd->pid != getpid()) {
hnd->base = 0;
hnd->lockState = 0;
hnd->writeOwner = 0;
}
return 0;
}
int gralloc_unregister_buffer(gralloc_module_t const* module,
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
/*
* If the buffer has been mapped during a lock operation, it's time
* to un-map it. It's an error to be here with a locked buffer.
* NOTE: the framebuffer is handled differently and is never unmapped.
*/
private_handle_t* hnd = (private_handle_t*)handle;
LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
"[unregister] handle %p still locked (state=%08x)",
hnd, hnd->lockState);
// never unmap buffers that were created in this process
if (hnd->pid != getpid()) {
if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
gralloc_unmap(module, handle);
}
hnd->base = 0;
hnd->lockState = 0;
hnd->writeOwner = 0;
}
return 0;
}
int terminateBuffer(gralloc_module_t const* module,
private_handle_t* hnd)
{
/*
* If the buffer has been mapped during a lock operation, it's time
* to un-map it. It's an error to be here with a locked buffer.
*/
LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
"[terminate] handle %p still locked (state=%08x)",
hnd, hnd->lockState);
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) {
if (hnd->pid != getpid()) {
// ... unless it's a "master" pmem buffer, that is a buffer
// mapped in the process it's been allocated.
// (see gralloc_alloc_buffer())
gralloc_unmap(module, hnd);
}
} else {
gralloc_unmap(module, hnd);
}
}
return 0;
}
int gralloc_lock(gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
int err = 0;
private_handle_t* hnd = (private_handle_t*)handle;
int32_t current_value, new_value;
int retry;
do {
current_value = hnd->lockState;
new_value = current_value;
if (current_value & private_handle_t::LOCK_STATE_WRITE) {
// already locked for write
LOGE("handle %p already locked for write", handle);
return -EBUSY;
} else if (current_value & private_handle_t::LOCK_STATE_READ_MASK) {
// already locked for read
if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
LOGE("handle %p already locked for read", handle);
return -EBUSY;
} else {
// this is not an error
//LOGD("%p already locked for read... count = %d",
// handle, (current_value & ~(1<<31)));
}
}
// not currently locked
if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
// locking for write
new_value |= private_handle_t::LOCK_STATE_WRITE;
}
new_value++;
retry = android_atomic_cmpxchg(current_value, new_value,
(volatile int32_t*)&hnd->lockState);
} while (retry);
if (new_value & private_handle_t::LOCK_STATE_WRITE) {
// locking for write, store the tid
hnd->writeOwner = gettid();
}
if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
if (!(current_value & private_handle_t::LOCK_STATE_MAPPED)) {
// we need to map for real
pthread_mutex_t* const lock = &sMapLock;
pthread_mutex_lock(lock);
if (!(hnd->lockState & private_handle_t::LOCK_STATE_MAPPED)) {
err = gralloc_map(module, handle, vaddr);
if (err == 0) {
android_atomic_or(private_handle_t::LOCK_STATE_MAPPED,
(volatile int32_t*)&(hnd->lockState));
}
}
pthread_mutex_unlock(lock);
}
*vaddr = (void*)hnd->base;
}
return err;
}
int gralloc_unlock(gralloc_module_t const* module,
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
private_handle_t* hnd = (private_handle_t*)handle;
int32_t current_value, new_value;
do {
current_value = hnd->lockState;
new_value = current_value;
if (current_value & private_handle_t::LOCK_STATE_WRITE) {
// locked for write
if (hnd->writeOwner == gettid()) {
hnd->writeOwner = 0;
new_value &= ~private_handle_t::LOCK_STATE_WRITE;
}
}
if ((new_value & private_handle_t::LOCK_STATE_READ_MASK) == 0) {
LOGE("handle %p not locked", handle);
return -EINVAL;
}
new_value--;
} while (android_atomic_cmpxchg(current_value, new_value,
(volatile int32_t*)&hnd->lockState));
return 0;
}
/*****************************************************************************/
int gralloc_perform(struct gralloc_module_t const* module,
int operation, ... )
{
int res = -EINVAL;
va_list args;
va_start(args, operation);
switch (operation) {
case GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER: {
int fd = va_arg(args, int);
size_t size = va_arg(args, size_t);
size_t offset = va_arg(args, size_t);
void* base = va_arg(args, void*);
native_handle_t** handle = va_arg(args, native_handle_t**);
private_handle_t* hnd = (private_handle_t*)native_handle_create(
private_handle_t::sNumFds, private_handle_t::sNumInts);
hnd->magic = private_handle_t::sMagic;
hnd->fd = fd;
hnd->flags = private_handle_t::PRIV_FLAGS_USES_PMEM;
hnd->size = size;
hnd->offset = offset;
hnd->base = intptr_t(base) + offset;
hnd->lockState = private_handle_t::LOCK_STATE_MAPPED;
*handle = (native_handle_t *)hnd;
res = 0;
break;
}
}
va_end(args);
return res;
}