From 81cd37b750a71dd0fb5d9e67dff39f2bfede765b Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Thu, 12 Nov 2009 18:46:07 -0800 Subject: [PATCH 1/2] eclair snapshot --- libcamera2/Android.mk | 35 - libcamera2/QualcommCameraHardware.cpp | 1946 ------------------------- libcamera2/QualcommCameraHardware.h | 241 --- libcopybit/Android.mk | 19 +- libcopybit/{copybit.c => copybit.cpp} | 128 +- libgralloc-qsd8k/Android.mk | 32 + libgralloc-qsd8k/allocator.cpp | 170 +++ libgralloc-qsd8k/allocator.h | 129 ++ libgralloc-qsd8k/framebuffer.cpp | 437 ++++++ libgralloc-qsd8k/gr.h | 63 + libgralloc-qsd8k/gralloc.cpp | 490 +++++++ libgralloc-qsd8k/gralloc_priv.h | 140 ++ libgralloc-qsd8k/mapper.cpp | 322 ++++ 13 files changed, 1900 insertions(+), 2252 deletions(-) delete mode 100644 libcamera2/Android.mk delete mode 100644 libcamera2/QualcommCameraHardware.cpp delete mode 100644 libcamera2/QualcommCameraHardware.h rename libcopybit/{copybit.c => copybit.cpp} (77%) create mode 100644 libgralloc-qsd8k/Android.mk create mode 100644 libgralloc-qsd8k/allocator.cpp create mode 100644 libgralloc-qsd8k/allocator.h create mode 100644 libgralloc-qsd8k/framebuffer.cpp create mode 100644 libgralloc-qsd8k/gr.h create mode 100644 libgralloc-qsd8k/gralloc.cpp create mode 100644 libgralloc-qsd8k/gralloc_priv.h create mode 100644 libgralloc-qsd8k/mapper.cpp diff --git a/libcamera2/Android.mk b/libcamera2/Android.mk deleted file mode 100644 index 80e24fe..0000000 --- a/libcamera2/Android.mk +++ /dev/null @@ -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 diff --git a/libcamera2/QualcommCameraHardware.cpp b/libcamera2/QualcommCameraHardware.cpp deleted file mode 100644 index 2a39f20..0000000 --- a/libcamera2/QualcommCameraHardware.cpp +++ /dev/null @@ -1,1946 +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. -*/ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "QualcommCameraHardware" -#include - -#include "QualcommCameraHardware.h" - -#include -#include -#include -#include -#include -#include -#if HAVE_ANDROID_OS -#include -#endif -#include - -#define LIKELY(exp) __builtin_expect(!!(exp), 1) -#define UNLIKELY(exp) __builtin_expect(!!(exp), 0) - -extern "C" { - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#define THUMBNAIL_WIDTH 512 -#define THUMBNAIL_HEIGHT 384 -#define THUMBNAIL_WIDTH_STR "512" -#define THUMBNAIL_HEIGHT_STR "384" -#define DEFAULT_PICTURE_WIDTH 2048 // 1280 -#define DEFAULT_PICTURE_HEIGHT 1536 // 768 -#define THUMBNAIL_BUFFER_SIZE (THUMBNAIL_WIDTH * THUMBNAIL_HEIGHT * 3/2) - -#define DEFAULT_PREVIEW_SETTING 2 // HVGA -#define PREVIEW_SIZE_COUNT (sizeof(preview_sizes)/sizeof(preview_size_type)) - -#define NOT_FOUND -1 - -#if DLOPEN_LIBMMCAMERA -#include - -void* (*LINK_cam_conf)(void *data); -void* (*LINK_cam_frame)(void *data); -bool (*LINK_jpeg_encoder_init)(); -void (*LINK_jpeg_encoder_join)(); -bool (*LINK_jpeg_encoder_encode)(const cam_ctrl_dimension_t *dimen, - const uint8_t *thumbnailbuf, int thumbnailfd, - const uint8_t *snapshotbuf, int snapshotfd, - common_crop_t *scaling_parms); -int (*LINK_camframe_terminate)(void); -int8_t (*LINK_jpeg_encoder_setMainImageQuality)(uint32_t quality); -int8_t (*LINK_jpeg_encoder_setThumbnailQuality)(uint32_t quality); -int8_t (*LINK_jpeg_encoder_setRotation)(uint32_t rotation); -int8_t (*LINK_jpeg_encoder_setLocation)(const camera_position_type *location); -// callbacks -void (**LINK_mmcamera_camframe_callback)(struct msm_frame *frame); -void (**LINK_mmcamera_jpegfragment_callback)(uint8_t *buff_ptr, - uint32_t buff_size); -void (**LINK_mmcamera_jpeg_callback)(jpeg_event_t status); -void (**LINK_mmcamera_shutter_callback)(); -#else -#define LINK_cam_conf cam_conf -#define LINK_cam_frame cam_frame -#define LINK_jpeg_encoder_init jpeg_encoder_init -#define LINK_jpeg_encoder_join jpeg_encoder_join -#define LINK_jpeg_encoder_encode jpeg_encoder_encode -#define LINK_camframe_terminate camframe_terminate -#define LINK_jpeg_encoder_setMainImageQuality jpeg_encoder_setMainImageQuality -#define LINK_jpeg_encoder_setThumbnailQuality jpeg_encoder_setThumbnailQuality -#define LINK_jpeg_encoder_setRotation jpeg_encoder_setRotation -#define LINK_jpeg_encoder_setLocation jpeg_encoder_setLocation -extern void (*mmcamera_camframe_callback)(struct msm_frame *frame); -extern void (*mmcamera_jpegfragment_callback)(uint8_t *buff_ptr, - uint32_t buff_size); -extern void (*mmcamera_jpeg_callback)(jpeg_event_t status); -extern void (*mmcamera_shutter_callback)(); -#endif - -} // extern "C" - -struct preview_size_type { - int width; - int height; -}; - -static preview_size_type preview_sizes[] = { - { 800, 480 }, // WVGA - { 640, 480 }, // VGA - { 480, 320 }, // HVGA - { 384, 288 }, - { 352, 288 }, // CIF - { 320, 240 }, // QVGA - { 240, 160 }, // SQVGA - { 176, 144 }, // QCIF -}; - -static int attr_lookup(const struct str_map *const arr, const char *name) -{ - if (name) { - const struct str_map *trav = arr; - while (trav->desc) { - if (!strcmp(trav->desc, name)) - return trav->val; - trav++; - } - } - return NOT_FOUND; -} - -#define INIT_VALUES_FOR(parm) do { \ - if (!parm##_values) { \ - parm##_values = (char *)malloc(sizeof(parm)/ \ - sizeof(parm[0])*30); \ - char *ptr = parm##_values; \ - const str_map *trav; \ - for (trav = parm; trav->desc; trav++) { \ - int len = strlen(trav->desc); \ - strcpy(ptr, trav->desc); \ - ptr += len; \ - *ptr++ = ','; \ - } \ - *--ptr = 0; \ - } \ -} while(0) - -// from aeecamera.h -static const str_map whitebalance[] = { - { "auto", CAMERA_WB_AUTO }, - { "incandescent", CAMERA_WB_INCANDESCENT }, - { "florescent", CAMERA_WB_FLUORESCENT }, - { "daylight", CAMERA_WB_DAYLIGHT }, - { "cloudy", CAMERA_WB_CLOUDY_DAYLIGHT }, - { "twilight", CAMERA_WB_TWILIGHT }, - { "shade", CAMERA_WB_SHADE }, - { NULL, 0 } -}; -static char *whitebalance_values; - -// from camera_effect_t -static const str_map effect[] = { - { "none", CAMERA_EFFECT_OFF }, /* This list must match aeecamera.h */ - { "mono", CAMERA_EFFECT_MONO }, - { "negative", CAMERA_EFFECT_NEGATIVE }, - { "solarize", CAMERA_EFFECT_SOLARIZE }, - { "sepia", CAMERA_EFFECT_SEPIA }, - { "posterize", CAMERA_EFFECT_POSTERIZE }, - { "whiteboard", CAMERA_EFFECT_WHITEBOARD }, - { "blackboard", CAMERA_EFFECT_BLACKBOARD }, - { "aqua", CAMERA_EFFECT_AQUA }, - { NULL, 0 } -}; -static char *effect_values; - -// from qcamera/common/camera.h -static const str_map antibanding[] = { - { "off", CAMERA_ANTIBANDING_OFF }, - { NULL, 0 } -}; -static char *antibanding_values; - -// round to the next power of two -static inline unsigned clp2(unsigned x) -{ - x = x - 1; - x = x | (x >> 1); - x = x | (x >> 2); - x = x | (x >> 4); - x = x | (x >> 8); - x = x | (x >>16); - return x + 1; -} - -namespace android { - -static Mutex singleton_lock; -static bool singleton_releasing; -static Condition singleton_wait; - -static void receive_camframe_callback(struct msm_frame *frame); -static void receive_jpeg_fragment_callback(uint8_t *buff_ptr, uint32_t buff_size); -static void receive_jpeg_callback(jpeg_event_t status); -static void receive_shutter_callback(); - -QualcommCameraHardware::QualcommCameraHardware() - : mParameters(), - mPreviewHeight(-1), - mPreviewWidth(-1), - mRawHeight(-1), - mRawWidth(-1), - mCameraRunning(false), - mPreviewInitialized(false), - mFrameThreadRunning(false), - mSnapshotThreadRunning(false), - mReleasedRecordingFrame(false), - mShutterCallback(0), - mRawPictureCallback(0), - mJpegPictureCallback(0), - mPictureCallbackCookie(0), - mAutoFocusCallback(0), - mAutoFocusCallbackCookie(0), - mPreviewCallback(0), - mPreviewCallbackCookie(0), - mRecordingCallback(0), - mRecordingCallbackCookie(0), - mPreviewFrameSize(0), - mRawSize(0), - mCameraControlFd(-1), - mAutoFocusThreadRunning(false), - mAutoFocusFd(-1), - mInPreviewCallback(false) -{ - memset(&mDimension, 0, sizeof(mDimension)); - memset(&mCrop, 0, sizeof(mCrop)); - LOGV("constructor EX"); -} - -void QualcommCameraHardware::initDefaultParameters() -{ - CameraParameters p; - - LOGV("initDefaultParameters E"); - - preview_size_type *ps = &preview_sizes[DEFAULT_PREVIEW_SETTING]; - p.setPreviewSize(ps->width, ps->height); - p.setPreviewFrameRate(15); - p.setPreviewFormat("yuv420sp"); // informative - p.setPictureFormat("jpeg"); // informative - - p.set("jpeg-quality", "100"); // maximum quality - p.set("jpeg-thumbnail-width", THUMBNAIL_WIDTH_STR); // informative - p.set("jpeg-thumbnail-height", THUMBNAIL_HEIGHT_STR); // informative - p.set("jpeg-thumbnail-quality", "90"); - - p.setPictureSize(DEFAULT_PICTURE_WIDTH, DEFAULT_PICTURE_HEIGHT); - p.set("antibanding", "off"); - p.set("effect", "none"); - p.set("whitebalance", "auto"); - -#if 0 - p.set("gps-timestamp", "1199145600"); // Jan 1, 2008, 00:00:00 - p.set("gps-latitude", "37.736071"); // A little house in San Francisco - p.set("gps-longitude", "-122.441983"); - p.set("gps-altitude", "21"); // meters -#endif - - // This will happen only one in the lifetime of the mediaserver process. - // We do not free the _values arrays when we destroy the camera object. - INIT_VALUES_FOR(antibanding); - INIT_VALUES_FOR(effect); - INIT_VALUES_FOR(whitebalance); - - p.set("antibanding-values", antibanding_values); - p.set("effect-values", effect_values); - p.set("whitebalance-values", whitebalance_values); - p.set("picture-size-values", "2048x1536,1600x1200,1024x768"); - - if (setParameters(p) != NO_ERROR) { - LOGE("Failed to set default parameters?!"); - } - - LOGV("initDefaultParameters X"); -} - -#define ROUND_TO_PAGE(x) (((x)+0xfff)&~0xfff) - -void QualcommCameraHardware::startCamera() -{ - LOGV("startCamera E"); -#if DLOPEN_LIBMMCAMERA - libmmcamera = ::dlopen("libqcamera.so", RTLD_NOW); - LOGV("loading libqcamera at %p", libmmcamera); - if (!libmmcamera) { - LOGE("FATAL ERROR: could not dlopen libqcamera.so: %s", dlerror()); - return; - } - - *(void **)&LINK_cam_frame = - ::dlsym(libmmcamera, "cam_frame"); - *(void **)&LINK_camframe_terminate = - ::dlsym(libmmcamera, "camframe_terminate"); - - *(void **)&LINK_jpeg_encoder_init = - ::dlsym(libmmcamera, "jpeg_encoder_init"); - - *(void **)&LINK_jpeg_encoder_encode = - ::dlsym(libmmcamera, "jpeg_encoder_encode"); - - *(void **)&LINK_jpeg_encoder_join = - ::dlsym(libmmcamera, "jpeg_encoder_join"); - - *(void **)&LINK_mmcamera_camframe_callback = - ::dlsym(libmmcamera, "mmcamera_camframe_callback"); - - *LINK_mmcamera_camframe_callback = receive_camframe_callback; - - *(void **)&LINK_mmcamera_jpegfragment_callback = - ::dlsym(libmmcamera, "mmcamera_jpegfragment_callback"); - - *LINK_mmcamera_jpegfragment_callback = receive_jpeg_fragment_callback; - - *(void **)&LINK_mmcamera_jpeg_callback = - ::dlsym(libmmcamera, "mmcamera_jpeg_callback"); - - *LINK_mmcamera_jpeg_callback = receive_jpeg_callback; - - *(void **)&LINK_mmcamera_shutter_callback = - ::dlsym(libmmcamera, "mmcamera_shutter_callback"); - - *LINK_mmcamera_shutter_callback = receive_shutter_callback; - - *(void**)&LINK_jpeg_encoder_setMainImageQuality = - ::dlsym(libmmcamera, "jpeg_encoder_setMainImageQuality"); - - *(void**)&LINK_jpeg_encoder_setThumbnailQuality = - ::dlsym(libmmcamera, "jpeg_encoder_setThumbnailQuality"); - - *(void**)&LINK_jpeg_encoder_setRotation = - ::dlsym(libmmcamera, "jpeg_encoder_setRotation"); - - *(void**)&LINK_jpeg_encoder_setLocation = - ::dlsym(libmmcamera, "jpeg_encoder_setLocation"); - - *(void **)&LINK_cam_conf = - ::dlsym(libmmcamera, "cam_conf"); -#else - mmcamera_camframe_callback = receive_camframe_callback; - mmcamera_jpegfragment_callback = receive_jpeg_fragment_callback; - mmcamera_jpeg_callback = receive_jpeg_callback; - mmcamera_shutter_callback = receive_shutter_callback; -#endif // DLOPEN_LIBMMCAMERA - - /* The control thread is in libcamera itself. */ - mCameraControlFd = open(MSM_CAMERA_CONTROL, O_RDWR); - if (mCameraControlFd < 0) { - LOGE("startCamera X: %s open failed: %s!", - MSM_CAMERA_CONTROL, - strerror(errno)); - return; - } - - pthread_create(&mCamConfigThread, NULL, - LINK_cam_conf, NULL); - - LOGV("startCamera X"); -} - -status_t QualcommCameraHardware::dump(int fd, - const Vector& args) const -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - // Dump internal primitives. - result.append("QualcommCameraHardware::dump"); - snprintf(buffer, 255, "preview width(%d) x height (%d)\n", - mPreviewWidth, mPreviewHeight); - result.append(buffer); - snprintf(buffer, 255, "raw width(%d) x height (%d)\n", - mRawWidth, mRawHeight); - result.append(buffer); - snprintf(buffer, 255, - "preview frame size(%d), raw size (%d), jpeg size (%d) " - "and jpeg max size (%d)\n", mPreviewFrameSize, mRawSize, - mJpegSize, mJpegMaxSize); - result.append(buffer); - write(fd, result.string(), result.size()); - - // Dump internal objects. - if (mPreviewHeap != 0) { - mPreviewHeap->dump(fd, args); - } - if (mRawHeap != 0) { - mRawHeap->dump(fd, args); - } - if (mJpegHeap != 0) { - mJpegHeap->dump(fd, args); - } - mParameters.dump(fd, args); - return NO_ERROR; -} - -static bool native_set_afmode(int camfd, isp3a_af_mode_t af_type) -{ - int rc; - struct msm_ctrl_cmd ctrlCmd; - - ctrlCmd.timeout_ms = 5000; - ctrlCmd.type = CAMERA_SET_PARM_AUTO_FOCUS; - ctrlCmd.length = sizeof(af_type); - ctrlCmd.value = &af_type; - ctrlCmd.resp_fd = camfd; // FIXME: this will be put in by the kernel - - if ((rc = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd)) < 0) - LOGE("native_set_afmode: ioctl fd %d error %s\n", - camfd, - strerror(errno)); - - LOGV("native_set_afmode: ctrlCmd.status == %d\n", ctrlCmd.status); - return rc >= 0 && ctrlCmd.status == CAMERA_EXIT_CB_DONE; -} - -static bool native_cancel_afmode(int camfd, int af_fd) -{ - int rc; - struct msm_ctrl_cmd ctrlCmd; - - ctrlCmd.timeout_ms = 5000; - ctrlCmd.type = CAMERA_AUTO_FOCUS_CANCEL; - ctrlCmd.length = 0; - ctrlCmd.resp_fd = af_fd; - - if ((rc = ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND_2, &ctrlCmd)) < 0) - LOGE("native_cancel_afmode: ioctl fd %d error %s\n", - camfd, - strerror(errno)); - return rc >= 0; -} - -static bool native_start_preview(int camfd) -{ - struct msm_ctrl_cmd ctrlCmd; - - ctrlCmd.timeout_ms = 5000; - ctrlCmd.type = CAMERA_START_PREVIEW; - ctrlCmd.length = 0; - ctrlCmd.resp_fd = camfd; // FIXME: this will be put in by the kernel - - if (ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0) { - LOGE("native_start_preview: MSM_CAM_IOCTL_CTRL_COMMAND fd %d error %s", - camfd, - strerror(errno)); - return false; - } - - return true; -} - -static bool native_get_picture (int camfd, common_crop_t *crop) -{ - struct msm_ctrl_cmd ctrlCmd; - - ctrlCmd.timeout_ms = 5000; - ctrlCmd.length = sizeof(common_crop_t); - ctrlCmd.value = crop; - - if(ioctl(camfd, MSM_CAM_IOCTL_GET_PICTURE, &ctrlCmd) < 0) { - LOGE("native_get_picture: MSM_CAM_IOCTL_GET_PICTURE fd %d error %s", - camfd, - strerror(errno)); - return false; - } - - LOGV("crop: in1_w %d", crop->in1_w); - LOGV("crop: in1_h %d", crop->in1_h); - LOGV("crop: out1_w %d", crop->out1_w); - LOGV("crop: out1_h %d", crop->out1_h); - - LOGV("crop: in2_w %d", crop->in2_w); - LOGV("crop: in2_h %d", crop->in2_h); - LOGV("crop: out2_w %d", crop->out2_w); - LOGV("crop: out2_h %d", crop->out2_h); - - LOGV("crop: update %d", crop->update_flag); - - return true; -} - -static bool native_stop_preview(int camfd) -{ - struct msm_ctrl_cmd ctrlCmd; - ctrlCmd.timeout_ms = 5000; - ctrlCmd.type = CAMERA_STOP_PREVIEW; - ctrlCmd.length = 0; - ctrlCmd.resp_fd = camfd; // FIXME: this will be put in by the kernel - - if(ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0) { - LOGE("native_stop_preview: ioctl fd %d error %s", - camfd, - strerror(errno)); - return false; - } - - return true; -} - -static bool native_start_snapshot(int camfd) -{ - struct msm_ctrl_cmd ctrlCmd; - - ctrlCmd.timeout_ms = 5000; - ctrlCmd.type = CAMERA_START_SNAPSHOT; - ctrlCmd.length = 0; - ctrlCmd.resp_fd = camfd; // FIXME: this will be put in by the kernel - - if(ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0) { - LOGE("native_start_snapshot: ioctl fd %d error %s", - camfd, - strerror(errno)); - return false; - } - - return true; -} - -static bool native_stop_snapshot (int camfd) -{ - struct msm_ctrl_cmd ctrlCmd; - - ctrlCmd.timeout_ms = 5000; - ctrlCmd.type = CAMERA_STOP_SNAPSHOT; - ctrlCmd.length = 0; - ctrlCmd.resp_fd = camfd; // FIXME: this will be put in by the kernel - - if (ioctl(camfd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0) { - LOGE("native_stop_snapshot: ioctl fd %d error %s", - camfd, - strerror(errno)); - return false; - } - - return true; -} - -bool QualcommCameraHardware::native_jpeg_encode(void) -{ - int jpeg_quality = mParameters.getInt("jpeg-quality"); - if (jpeg_quality >= 0) { - LOGV("native_jpeg_encode, current jpeg main img quality =%d", - jpeg_quality); - if(!LINK_jpeg_encoder_setMainImageQuality(jpeg_quality)) { - LOGE("native_jpeg_encode set jpeg-quality failed"); - return false; - } - } - - int thumbnail_quality = mParameters.getInt("jpeg-thumbnail-quality"); - if (thumbnail_quality >= 0) { - LOGV("native_jpeg_encode, current jpeg thumbnail quality =%d", - thumbnail_quality); - if(!LINK_jpeg_encoder_setThumbnailQuality(thumbnail_quality)) { - LOGE("native_jpeg_encode set thumbnail-quality failed"); - return false; - } - } - - int rotation = mParameters.getInt("rotation"); - if (rotation >= 0) { - LOGV("native_jpeg_encode, rotation = %d", rotation); - if(!LINK_jpeg_encoder_setRotation(rotation)) { - LOGE("native_jpeg_encode set rotation failed"); - return false; - } - } - - jpeg_set_location(); - - if (!LINK_jpeg_encoder_encode(&mDimension, - (uint8_t *)mThumbnailHeap->mHeap->base(), - mThumbnailHeap->mHeap->getHeapID(), - (uint8_t *)mRawHeap->mHeap->base(), - mRawHeap->mHeap->getHeapID(), - &mCrop)) { - LOGE("native_jpeg_encode: jpeg_encoder_encode failed."); - return false; - } - return true; -} - -bool QualcommCameraHardware::native_set_dimension(cam_ctrl_dimension_t *value) -{ - return native_set_parm(CAMERA_SET_PARM_DIMENSION, - sizeof(cam_ctrl_dimension_t), value); -} - -bool QualcommCameraHardware::native_set_parm( - cam_ctrl_type type, uint16_t length, void *value) -{ - int rc = true; - struct msm_ctrl_cmd ctrlCmd; - - ctrlCmd.timeout_ms = 5000; - ctrlCmd.type = (uint16_t)type; - ctrlCmd.length = length; - // FIXME: this will be put in by the kernel - ctrlCmd.resp_fd = mCameraControlFd; - ctrlCmd.value = value; - - LOGV("native_set_parm. camfd=%d, type=%d, length=%d", - mCameraControlFd, type, length); - rc = ioctl(mCameraControlFd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd); - if(rc < 0 || ctrlCmd.status != CAM_CTRL_SUCCESS) { - LOGE("ioctl error. camfd=%d, type=%d, length=%d, rc=%d, ctrlCmd.status=%d, %s", - mCameraControlFd, type, length, rc, ctrlCmd.status, strerror(errno)); - return false; - } - return true; -} - -void QualcommCameraHardware::jpeg_set_location() -{ - bool encode_location = true; - camera_position_type pt; - -#define PARSE_LOCATION(what,type,fmt,desc) do { \ - pt.what = 0; \ - const char *what##_str = mParameters.get("gps-"#what); \ - LOGV("GPS PARM %s --> [%s]", "gps-"#what, what##_str); \ - if (what##_str) { \ - type what = 0; \ - if (sscanf(what##_str, fmt, &what) == 1) \ - pt.what = what; \ - else { \ - LOGE("GPS " #what " %s could not" \ - " be parsed as a " #desc, what##_str); \ - encode_location = false; \ - } \ - } \ - else { \ - LOGV("GPS " #what " not specified: " \ - "defaulting to zero in EXIF header."); \ - encode_location = false; \ - } \ - } while(0) - - PARSE_LOCATION(timestamp, long, "%ld", "long"); - if (!pt.timestamp) pt.timestamp = time(NULL); - PARSE_LOCATION(altitude, short, "%hd", "short"); - PARSE_LOCATION(latitude, double, "%lf", "double float"); - PARSE_LOCATION(longitude, double, "%lf", "double float"); - -#undef PARSE_LOCATION - - if (encode_location) { - LOGD("setting image location ALT %d LAT %lf LON %lf", - pt.altitude, pt.latitude, pt.longitude); - if (!LINK_jpeg_encoder_setLocation(&pt)) { - LOGE("jpeg_set_location: LINK_jpeg_encoder_setLocation failed."); - } - } - else LOGV("not setting image location"); -} - -void QualcommCameraHardware::runFrameThread(void *data) -{ - LOGV("runFrameThread E"); - - int cnt; - -#if DLOPEN_LIBMMCAMERA - // We need to maintain a reference to libqcamera.so for the duration of the - // frame thread, because we do not know when it will exit relative to the - // lifetime of this object. We do not want to dlclose() libqcamera while - // LINK_cam_frame is still running. - void *libhandle = ::dlopen("libqcamera.so", RTLD_NOW); - LOGV("FRAME: loading libqcamera at %p", libhandle); - if (!libhandle) { - LOGE("FATAL ERROR: could not dlopen libqcamera.so: %s", dlerror()); - } - if (libhandle) -#endif - { - LINK_cam_frame(data); - } - - mPreviewHeap.clear(); - -#if DLOPEN_LIBMMCAMERA - if (libhandle) { - ::dlclose(libhandle); - LOGV("FRAME: dlclose(libqcamera)"); - } -#endif - - mFrameThreadWaitLock.lock(); - mFrameThreadRunning = false; - mFrameThreadWait.signal(); - mFrameThreadWaitLock.unlock(); - - LOGV("runFrameThread X"); -} - -void *frame_thread(void *user) -{ - LOGD("frame_thread E"); - sp obj = QualcommCameraHardware::getInstance(); - if (obj != 0) { - obj->runFrameThread(user); - } - else LOGW("not starting frame thread: the object went away!"); - LOGD("frame_thread X"); - return NULL; -} - -bool QualcommCameraHardware::initPreview() -{ - // See comments in deinitPreview() for why we have to wait for the frame - // thread here, and why we can't use pthread_join(). - LOGI("initPreview E: preview size=%dx%d", mPreviewWidth, mPreviewHeight); - mFrameThreadWaitLock.lock(); - while (mFrameThreadRunning) { - LOGV("initPreview: waiting for old frame thread to complete."); - mFrameThreadWait.wait(mFrameThreadWaitLock); - LOGV("initPreview: old frame thread completed."); - } - mFrameThreadWaitLock.unlock(); - - mSnapshotThreadWaitLock.lock(); - while (mSnapshotThreadRunning) { - LOGV("initPreview: waiting for old snapshot thread to complete."); - mSnapshotThreadWait.wait(mSnapshotThreadWaitLock); - LOGV("initPreview: old snapshot thread completed."); - } - mSnapshotThreadWaitLock.unlock(); - - int cnt = 0; - mPreviewFrameSize = mPreviewWidth * mPreviewHeight * 3/2; - mPreviewHeap = new PmemPool("/dev/pmem_adsp", - mCameraControlFd, - MSM_PMEM_OUTPUT2, - mPreviewFrameSize, - kPreviewBufferCount, - mPreviewFrameSize, - 0, - "preview"); - - if (!mPreviewHeap->initialized()) { - mPreviewHeap.clear(); - LOGE("initPreview X: could not initialize preview heap."); - return false; - } - - mDimension.picture_width = DEFAULT_PICTURE_WIDTH; - mDimension.picture_height = DEFAULT_PICTURE_HEIGHT; - - bool ret = native_set_dimension(&mDimension); - - if (ret) { - for (cnt = 0; cnt < kPreviewBufferCount; cnt++) { - frames[cnt].fd = mPreviewHeap->mHeap->getHeapID(); - frames[cnt].buffer = - (uint32_t)mPreviewHeap->mHeap->base() + mPreviewFrameSize * cnt; - frames[cnt].y_off = 0; - frames[cnt].cbcr_off = mPreviewWidth * mPreviewHeight; - frames[cnt].path = MSM_FRAME_ENC; - } - - mFrameThreadWaitLock.lock(); - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - mFrameThreadRunning = !pthread_create(&mFrameThread, - &attr, - frame_thread, - &frames[kPreviewBufferCount-1]); - ret = mFrameThreadRunning; - mFrameThreadWaitLock.unlock(); - } - - LOGV("initPreview X: %d", ret); - return ret; -} - -void QualcommCameraHardware::deinitPreview(void) -{ - LOGI("deinitPreview E"); - - // When we call deinitPreview(), we signal to the frame thread that it - // needs to exit, but we DO NOT WAIT for it to complete here. The problem - // is that deinitPreview is sometimes called from the frame-thread's - // callback, when the refcount on the Camera client reaches zero. If we - // called pthread_join(), we would deadlock. So, we just call - // LINK_camframe_terminate() in deinitPreview(), which makes sure that - // after the preview callback returns, the camframe thread will exit. We - // could call pthread_join() in initPreview() to join the last frame - // thread. However, we would also have to call pthread_join() in release - // as well, shortly before we destoy the object; this would cause the same - // deadlock, since release(), like deinitPreview(), may also be called from - // the frame-thread's callback. This we have to make the frame thread - // detached, and use a separate mechanism to wait for it to complete. - - if (LINK_camframe_terminate() < 0) - LOGE("failed to stop the camframe thread: %s", - strerror(errno)); - LOGI("deinitPreview X"); -} - -bool QualcommCameraHardware::initRaw(bool initJpegHeap) -{ - LOGV("initRaw E: picture size=%dx%d", - mRawWidth, mRawHeight); - - mDimension.picture_width = mRawWidth; - mDimension.picture_height = mRawHeight; - mRawSize = mRawWidth * mRawHeight * 3 / 2; - mJpegMaxSize = mRawWidth * mRawHeight * 3 / 2; - - if(!native_set_dimension(&mDimension)) { - LOGE("initRaw X: failed to set dimension"); - return false; - } - - if (mJpegHeap != NULL) { - LOGV("initRaw: clearing old mJpegHeap."); - mJpegHeap.clear(); - } - - // Snapshot - - LOGV("initRaw: initializing mRawHeap."); - mRawHeap = - new PmemPool("/dev/pmem_camera", - mCameraControlFd, - MSM_PMEM_MAINIMG, - mJpegMaxSize, - kRawBufferCount, - mRawSize, - 0, - "snapshot camera"); - - if (!mRawHeap->initialized()) { - LOGE("initRaw X failed with pmem_camera, trying with pmem_adsp"); - mRawHeap = - new PmemPool("/dev/pmem_adsp", - mCameraControlFd, - MSM_PMEM_MAINIMG, - mJpegMaxSize, - kRawBufferCount, - mRawSize, - 0, - "snapshot camera"); - if (!mRawHeap->initialized()) { - mRawHeap.clear(); - LOGE("initRaw X: error initializing mRawHeap"); - return false; - } - } - - LOGV("do_mmap snapshot pbuf = %p, pmem_fd = %d", - (uint8_t *)mRawHeap->mHeap->base(), mRawHeap->mHeap->getHeapID()); - - // Jpeg - - if (initJpegHeap) { - LOGV("initRaw: initializing mJpegHeap."); - mJpegHeap = - new AshmemPool(mJpegMaxSize, - kJpegBufferCount, - 0, // we do not know how big the picture wil be - 0, - "jpeg"); - - if (!mJpegHeap->initialized()) { - mJpegHeap.clear(); - mRawHeap.clear(); - LOGE("initRaw X failed: error initializing mJpegHeap."); - return false; - } - - // Thumbnails - - mThumbnailHeap = - new PmemPool("/dev/pmem_adsp", - mCameraControlFd, - MSM_PMEM_THUMBAIL, - THUMBNAIL_BUFFER_SIZE, - 1, - THUMBNAIL_BUFFER_SIZE, - 0, - "thumbnail"); - - if (!mThumbnailHeap->initialized()) { - mThumbnailHeap.clear(); - mJpegHeap.clear(); - mRawHeap.clear(); - LOGE("initRaw X failed: error initializing mThumbnailHeap."); - return false; - } - } - - LOGV("initRaw X"); - return true; -} - -void QualcommCameraHardware::deinitRaw() -{ - LOGV("deinitRaw E"); - - mThumbnailHeap.clear(); - mJpegHeap.clear(); - mRawHeap.clear(); - - LOGV("deinitRaw X"); -} - -void QualcommCameraHardware::release() -{ - LOGD("release E"); - Mutex::Autolock l(&mLock); - -#if DLOPEN_LIBMMCAMERA - if (libmmcamera == NULL) { - LOGE("ERROR: multiple release!"); - return; - } -#else -#warning "Cannot detect multiple release when not dlopen()ing libqcamera!" -#endif - - int cnt, rc; - struct msm_ctrl_cmd ctrlCmd; - - if (mCameraRunning) { - if(mRecordingCallback != NULL) { - mRecordFrameLock.lock(); - mReleasedRecordingFrame = true; - mRecordWait.signal(); - mRecordFrameLock.unlock(); - } - stopPreviewInternal(); - } - - LINK_jpeg_encoder_join(); - deinitRaw(); - - ctrlCmd.timeout_ms = 5000; - ctrlCmd.length = 0; - ctrlCmd.type = (uint16_t)CAMERA_EXIT; - ctrlCmd.resp_fd = mCameraControlFd; // FIXME: this will be put in by the kernel - if (ioctl(mCameraControlFd, MSM_CAM_IOCTL_CTRL_COMMAND, &ctrlCmd) < 0) - LOGE("ioctl CAMERA_EXIT fd %d error %s", - mCameraControlFd, strerror(errno)); - rc = pthread_join(mCamConfigThread, NULL); - if (rc) - LOGE("config_thread exit failure: %s", strerror(errno)); - else - LOGV("pthread_join succeeded on config_thread"); - - close(mCameraControlFd); - mCameraControlFd = -1; - -#if DLOPEN_LIBMMCAMERA - if (libmmcamera) { - ::dlclose(libmmcamera); - LOGV("dlclose(libqcamera)"); - libmmcamera = NULL; - } -#endif - - Mutex::Autolock lock(&singleton_lock); - singleton_releasing = true; - - LOGD("release X"); -} - -QualcommCameraHardware::~QualcommCameraHardware() -{ - LOGD("~QualcommCameraHardware E"); - Mutex::Autolock lock(&singleton_lock); - singleton.clear(); - singleton_releasing = false; - singleton_wait.signal(); - LOGD("~QualcommCameraHardware X"); -} - -sp QualcommCameraHardware::getRawHeap() const -{ - LOGV("getRawHeap"); - return mRawHeap != NULL ? mRawHeap->mHeap : NULL; -} - -sp QualcommCameraHardware::getPreviewHeap() const -{ - LOGV("getPreviewHeap"); - return mPreviewHeap != NULL ? mPreviewHeap->mHeap : NULL; -} - -status_t QualcommCameraHardware::startPreviewInternal() -{ - if(mCameraRunning) { - LOGV("startPreview X: preview already running."); - return NO_ERROR; - } - - if (!mPreviewInitialized) { - mPreviewInitialized = initPreview(); - if (!mPreviewInitialized) { - LOGE("startPreview X initPreview failed. Not starting preview."); - return UNKNOWN_ERROR; - } - } - - mCameraRunning = native_start_preview(mCameraControlFd); - if(!mCameraRunning) { - deinitPreview(); - mPreviewInitialized = false; - LOGE("startPreview X: native_start_preview failed!"); - return UNKNOWN_ERROR; - } - - LOGV("startPreview X"); - return NO_ERROR; -} - -status_t QualcommCameraHardware::startPreview(preview_callback cb, void *user) -{ - LOGV("startPreview E"); - Mutex::Autolock l(&mLock); - - { - Mutex::Autolock cbLock(&mCallbackLock); - mPreviewCallback = cb; - mPreviewCallbackCookie = user; - } - - return startPreviewInternal(); -} - -void QualcommCameraHardware::stopPreviewInternal() -{ - LOGV("stopPreviewInternal E: %d", mCameraRunning); - if (mCameraRunning) { - // Cancel auto focus. - if (mAutoFocusCallback) { - { - Mutex::Autolock cbLock(&mCallbackLock); - mAutoFocusCallback = NULL; - mAutoFocusCallbackCookie = NULL; - } - cancelAutoFocus(); - } - - mCameraRunning = !native_stop_preview(mCameraControlFd); - if (!mCameraRunning && mPreviewInitialized) { - deinitPreview(); - mPreviewInitialized = false; - } - else LOGE("stopPreviewInternal: failed to stop preview"); - } - LOGV("stopPreviewInternal X: %d", mCameraRunning); -} - -void QualcommCameraHardware::stopPreview() -{ - LOGV("stopPreview: E"); - Mutex::Autolock l(&mLock); - - { - Mutex::Autolock cbLock(&mCallbackLock); - mPreviewCallback = NULL; - mPreviewCallbackCookie = NULL; - if(mRecordingCallback != NULL) - return; - } - - stopPreviewInternal(); - - LOGV("stopPreview: X"); -} - -void QualcommCameraHardware::runAutoFocus() -{ - mAutoFocusThreadLock.lock(); - mAutoFocusFd = open(MSM_CAMERA_CONTROL, O_RDWR); - if (mAutoFocusFd < 0) { - LOGE("autofocus: cannot open %s: %s", - MSM_CAMERA_CONTROL, - strerror(errno)); - mAutoFocusThreadRunning = false; - mAutoFocusThreadLock.unlock(); - return; - } - -#if DLOPEN_LIBMMCAMERA - // We need to maintain a reference to libqcamera.so for the duration of the - // AF thread, because we do not know when it will exit relative to the - // lifetime of this object. We do not want to dlclose() libqcamera while - // LINK_cam_frame is still running. - void *libhandle = ::dlopen("libqcamera.so", RTLD_NOW); - LOGV("AF: loading libqcamera at %p", libhandle); - if (!libhandle) { - LOGE("FATAL ERROR: could not dlopen libqcamera.so: %s", dlerror()); - close(mAutoFocusFd); - mAutoFocusFd = -1; - mAutoFocusThreadRunning = false; - mAutoFocusThreadLock.unlock(); - return; - } -#endif - - /* This will block until either AF completes or is cancelled. */ - LOGV("af start (fd %d)", mAutoFocusFd); - bool status = native_set_afmode(mAutoFocusFd, AF_MODE_AUTO); - LOGV("af done: %d", (int)status); - mAutoFocusThreadRunning = false; - close(mAutoFocusFd); - mAutoFocusFd = -1; - mAutoFocusThreadLock.unlock(); - - mCallbackLock.lock(); - autofocus_callback cb = mAutoFocusCallback; - void *data = mAutoFocusCallbackCookie; - mCallbackLock.unlock(); - if (cb != NULL) - cb(status, data); - - mCallbackLock.lock(); - mAutoFocusCallback = NULL; - mAutoFocusCallbackCookie = NULL; - mCallbackLock.unlock(); - -#if DLOPEN_LIBMMCAMERA - if (libhandle) { - ::dlclose(libhandle); - LOGV("AF: dlclose(libqcamera)"); - } -#endif -} - -void QualcommCameraHardware::cancelAutoFocus() -{ - LOGV("cancelAutoFocus E"); - native_cancel_afmode(mCameraControlFd, mAutoFocusFd); - LOGV("cancelAutoFocus X"); -} - -void *auto_focus_thread(void *user) -{ - LOGV("auto_focus_thread E"); - sp obj = QualcommCameraHardware::getInstance(); - if (obj != 0) { - obj->runAutoFocus(); - } - else LOGW("not starting autofocus: the object went away!"); - LOGV("auto_focus_thread X"); - return NULL; -} - -status_t QualcommCameraHardware::autoFocus(autofocus_callback af_cb, - void *user) -{ - LOGV("autoFocus E"); - Mutex::Autolock l(&mLock); - - if (mCameraControlFd < 0) { - LOGE("not starting autofocus: main control fd %d", mCameraControlFd); - return UNKNOWN_ERROR; - } - - if (mAutoFocusCallback != NULL) { - LOGW("Auto focus is already in progress"); - return mAutoFocusCallback == af_cb ? NO_ERROR : INVALID_OPERATION; - } - - { - Mutex::Autolock cbl(&mCallbackLock); - mAutoFocusCallback = af_cb; - mAutoFocusCallbackCookie = user; - } - - { - mAutoFocusThreadLock.lock(); - if (!mAutoFocusThreadRunning) { - // Create a detatched thread here so that we don't have to wait - // for it when we cancel AF. - pthread_t thr; - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - mAutoFocusThreadRunning = - !pthread_create(&thr, &attr, - auto_focus_thread, NULL); - if (!mAutoFocusThreadRunning) { - LOGE("failed to start autofocus thread"); - mAutoFocusThreadLock.unlock(); - return UNKNOWN_ERROR; - } - } - mAutoFocusThreadLock.unlock(); - } - - LOGV("autoFocus X"); - return NO_ERROR; -} - -void QualcommCameraHardware::runSnapshotThread(void *data) -{ - LOGV("runSnapshotThread E"); - if (native_start_snapshot(mCameraControlFd)) - receiveRawPicture(); - else - LOGE("main: native_start_snapshot failed!"); - - mSnapshotThreadWaitLock.lock(); - mSnapshotThreadRunning = false; - mSnapshotThreadWait.signal(); - mSnapshotThreadWaitLock.unlock(); - - LOGV("runSnapshotThread X"); -} - -void *snapshot_thread(void *user) -{ - LOGD("snapshot_thread E"); - sp obj = QualcommCameraHardware::getInstance(); - if (obj != 0) { - obj->runSnapshotThread(user); - } - else LOGW("not starting snapshot thread: the object went away!"); - LOGD("snapshot_thread X"); - return NULL; -} - -status_t QualcommCameraHardware::takePicture(shutter_callback shutter_cb, - raw_callback raw_cb, - jpeg_callback jpeg_cb, - void *user) -{ - LOGV("takePicture: E raw_cb = %p, jpeg_cb = %p", - raw_cb, jpeg_cb); - Mutex::Autolock l(&mLock); - - // Wait for old snapshot thread to complete. - mSnapshotThreadWaitLock.lock(); - while (mSnapshotThreadRunning) { - LOGV("takePicture: waiting for old snapshot thread to complete."); - mSnapshotThreadWait.wait(mSnapshotThreadWaitLock); - LOGV("takePicture: old snapshot thread completed."); - } - - stopPreviewInternal(); - - if (!initRaw(jpeg_cb != NULL)) { - LOGE("initRaw failed. Not taking picture."); - return UNKNOWN_ERROR; - } - - { - Mutex::Autolock cbLock(&mCallbackLock); - mShutterCallback = shutter_cb; - mRawPictureCallback = raw_cb; - mJpegPictureCallback = jpeg_cb; - mPictureCallbackCookie = user; - } - - mShutterLock.lock(); - mShutterPending = true; - mShutterLock.unlock(); - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - mSnapshotThreadRunning = !pthread_create(&mSnapshotThread, - &attr, - snapshot_thread, - NULL); - mSnapshotThreadWaitLock.unlock(); - - LOGV("takePicture: X"); - return mSnapshotThreadRunning ? NO_ERROR : UNKNOWN_ERROR; -} - -status_t QualcommCameraHardware::cancelPicture( - bool cancel_shutter, bool cancel_raw, bool cancel_jpeg) -{ - LOGV("cancelPicture: E cancel_shutter = %d, " - "cancel_raw = %d, cancel_jpeg = %d", - cancel_shutter, cancel_raw, cancel_jpeg); - Mutex::Autolock l(&mLock); - - { - Mutex::Autolock cbLock(&mCallbackLock); - if (cancel_shutter) mShutterCallback = NULL; - if (cancel_raw) mRawPictureCallback = NULL; - if (cancel_jpeg) mJpegPictureCallback = NULL; - } - - LOGV("cancelPicture: X"); - return NO_ERROR; -} - -status_t QualcommCameraHardware::setParameters( - const CameraParameters& params) -{ - LOGV("setParameters: E params = %p", ¶ms); - - Mutex::Autolock l(&mLock); - - // Set preview size. - preview_size_type *ps = preview_sizes; - { - int width, height; - params.getPreviewSize(&width, &height); - LOGV("requested size %d x %d", width, height); - // Validate the preview size - size_t i; - for (i = 0; i < PREVIEW_SIZE_COUNT; ++i, ++ps) { - if (width == ps->width && height == ps->height) - break; - } - if (i == PREVIEW_SIZE_COUNT) { - LOGE("Invalid preview size requested: %dx%d", - width, height); - return BAD_VALUE; - } - } - mPreviewWidth = mDimension.display_width = ps->width; - mPreviewHeight = mDimension.display_height = ps->height; - - // FIXME: validate snapshot sizes, - params.getPictureSize(&mRawWidth, &mRawHeight); - mDimension.picture_width = mRawWidth; - mDimension.picture_height = mRawHeight; - - // Set up the jpeg-thumbnail-size parameters. - { - int val; - - val = params.getInt("jpeg-thumbnail-width"); - if (val < 0) { - mDimension.ui_thumbnail_width= THUMBNAIL_WIDTH; - LOGW("jpeg-thumbnail-width is not specified: defaulting to %d", - THUMBNAIL_WIDTH); - } - else mDimension.ui_thumbnail_width = val; - - val = params.getInt("jpeg-thumbnail-height"); - if (val < 0) { - mDimension.ui_thumbnail_height= THUMBNAIL_HEIGHT; - LOGW("jpeg-thumbnail-height is not specified: defaulting to %d", - THUMBNAIL_HEIGHT); - } - else mDimension.ui_thumbnail_height = val; - } - - mParameters = params; - - setAntibanding(); - setEffect(); - setWhiteBalance(); - // FIXME: set nightshot and luma adaptatiom - - LOGV("setParameters: X"); - return NO_ERROR ; -} - -CameraParameters QualcommCameraHardware::getParameters() const -{ - LOGV("getParameters: EX"); - return mParameters; -} - -extern "C" sp openCameraHardware() -{ - LOGV("openCameraHardware: call createInstance"); - return QualcommCameraHardware::createInstance(); -} - -wp QualcommCameraHardware::singleton; - -// If the hardware already exists, return a strong pointer to the current -// object. If not, create a new hardware object, put it in the singleton, -// and return it. -sp QualcommCameraHardware::createInstance() -{ - LOGD("createInstance: E"); - - Mutex::Autolock lock(&singleton_lock); - - // Wait until the previous release is done. - while (singleton_releasing) { - LOGD("Wait for previous release."); - singleton_wait.wait(singleton_lock); - } - - if (singleton != 0) { - sp hardware = singleton.promote(); - if (hardware != 0) { - LOGD("createInstance: X return existing hardware=%p", &(*hardware)); - return hardware; - } - } - - { - struct stat st; - int rc = stat("/dev/oncrpc", &st); - if (rc < 0) { - LOGD("createInstance: X failed to create hardware: %s", strerror(errno)); - return NULL; - } - } - - QualcommCameraHardware *cam = new QualcommCameraHardware(); - sp hardware(cam); - singleton = hardware; - - cam->startCamera(); - cam->initDefaultParameters(); - LOGD("createInstance: X created hardware=%p", &(*hardware)); - return hardware; -} - -// For internal use only, hence the strong pointer to the derived type. -sp QualcommCameraHardware::getInstance() -{ - sp hardware = singleton.promote(); - if (hardware != 0) { - // LOGV("getInstance: X old instance of hardware"); - return sp(static_cast(hardware.get())); - } else { - LOGV("getInstance: X new instance of hardware"); - return sp(); - } -} - -void QualcommCameraHardware::receivePreviewFrame(struct msm_frame *frame) -{ -// LOGV("receivePreviewFrame E"); - - if (!mCameraRunning) { - LOGE("ignoring preview callback--camera has been stopped"); - return; - } - - mCallbackLock.lock(); - preview_callback pcb = mPreviewCallback; - void *pdata = mPreviewCallbackCookie; - recording_callback rcb = mRecordingCallback; - void *rdata = mRecordingCallbackCookie; - mCallbackLock.unlock(); - - // Find the offset within the heap of the current buffer. - ssize_t offset = - (ssize_t)frame->buffer - (ssize_t)mPreviewHeap->mHeap->base(); - offset /= mPreviewFrameSize; - - //LOGV("%d\n", offset); - - mInPreviewCallback = true; - if (pcb != NULL) - pcb(mPreviewHeap->mBuffers[offset], - pdata); - - if(rcb != NULL) { - Mutex::Autolock rLock(&mRecordFrameLock); - rcb(systemTime(), mPreviewHeap->mBuffers[offset], rdata); - if (mReleasedRecordingFrame != true) { - LOGV("block for release frame request/command"); - mRecordWait.wait(mRecordFrameLock); - } - mReleasedRecordingFrame = false; - } - mInPreviewCallback = false; - -// LOGV("receivePreviewFrame X"); -} - -status_t QualcommCameraHardware::startRecording( - recording_callback rcb, void *ruser) -{ - LOGV("startRecording E"); - Mutex::Autolock l(&mLock); - - { - Mutex::Autolock cbLock(&mCallbackLock); - mRecordingCallback = rcb; - mRecordingCallbackCookie = ruser; - } - - mReleasedRecordingFrame = false; - - return startPreviewInternal(); -} - -void QualcommCameraHardware::stopRecording() -{ - LOGV("stopRecording: E"); - Mutex::Autolock l(&mLock); - - { - Mutex::Autolock cbLock(&mCallbackLock); - mRecordingCallback = NULL; - mRecordingCallbackCookie = NULL; - - mRecordFrameLock.lock(); - mReleasedRecordingFrame = true; - mRecordWait.signal(); - mRecordFrameLock.unlock(); - - if(mPreviewCallback != NULL) { - LOGV("stopRecording: X, preview still in progress"); - return; - } - } - - stopPreviewInternal(); - LOGV("stopRecording: X"); -} - -void QualcommCameraHardware::releaseRecordingFrame( - const sp& mem __attribute__((unused))) -{ - LOGV("releaseRecordingFrame E"); - Mutex::Autolock l(&mLock); - Mutex::Autolock rLock(&mRecordFrameLock); - mReleasedRecordingFrame = true; - mRecordWait.signal(); - LOGV("releaseRecordingFrame X"); -} - -bool QualcommCameraHardware::recordingEnabled() -{ - Mutex::Autolock l(&mLock); - return mCameraRunning && mRecordingCallback != NULL; -} - -void QualcommCameraHardware::notifyShutter() -{ - mShutterLock.lock(); - if (mShutterPending && mShutterCallback) { - mShutterCallback(mPictureCallbackCookie); - mShutterPending = false; - } - mShutterLock.unlock(); -} - -static void receive_shutter_callback() -{ - LOGV("receive_shutter_callback: E"); - sp obj = QualcommCameraHardware::getInstance(); - if (obj != 0) { - obj->notifyShutter(); - } - LOGV("receive_shutter_callback: X"); -} - -void QualcommCameraHardware::receiveRawPicture() -{ - LOGV("receiveRawPicture: E"); - - Mutex::Autolock cbLock(&mCallbackLock); - - if (mRawPictureCallback != NULL) { - if(native_get_picture(mCameraControlFd, &mCrop) == false) { - LOGE("getPicture failed!"); - return; - } - - // By the time native_get_picture returns, picture is taken. Call - // shutter callback if cam config thread has not done that. - notifyShutter(); - mRawPictureCallback(mRawHeap->mBuffers[0], - mPictureCallbackCookie); - } - else LOGV("Raw-picture callback was canceled--skipping."); - - if (mJpegPictureCallback != NULL) { - mJpegSize = 0; - if (LINK_jpeg_encoder_init()) { - if(native_jpeg_encode()) { - LOGV("receiveRawPicture: X (success)"); - return; - } - LOGE("jpeg encoding failed"); - } - else LOGE("receiveRawPicture X: jpeg_encoder_init failed."); - } - else LOGV("JPEG callback is NULL, not encoding image."); - deinitRaw(); - LOGV("receiveRawPicture: X"); -} - -void QualcommCameraHardware::receiveJpegPictureFragment( - uint8_t *buff_ptr, uint32_t buff_size) -{ - uint32_t remaining = mJpegHeap->mHeap->virtualSize(); - remaining -= mJpegSize; - uint8_t *base = (uint8_t *)mJpegHeap->mHeap->base(); - - LOGV("receiveJpegPictureFragment size %d", buff_size); - if (buff_size > remaining) { - LOGE("receiveJpegPictureFragment: size %d exceeds what " - "remains in JPEG heap (%d), truncating", - buff_size, - remaining); - buff_size = remaining; - } - memcpy(base + mJpegSize, buff_ptr, buff_size); - mJpegSize += buff_size; -} - -void QualcommCameraHardware::receiveJpegPicture(void) -{ - LOGV("receiveJpegPicture: E image (%d uint8_ts out of %d)", - mJpegSize, mJpegHeap->mBufferSize); - Mutex::Autolock cbLock(&mCallbackLock); - - int index = 0, rc; - - if (mJpegPictureCallback) { - // The reason we do not allocate into mJpegHeap->mBuffers[offset] is - // that the JPEG image's size will probably change from one snapshot - // to the next, so we cannot reuse the MemoryBase object. - sp buffer = new - MemoryBase(mJpegHeap->mHeap, - index * mJpegHeap->mBufferSize + - mJpegHeap->mFrameOffset, - mJpegSize); - - mJpegPictureCallback(buffer, mPictureCallbackCookie); - buffer = NULL; - } - else LOGV("JPEG callback was cancelled--not delivering image."); - - LINK_jpeg_encoder_join(); - deinitRaw(); - - LOGV("receiveJpegPicture: X callback done."); -} - -bool QualcommCameraHardware::previewEnabled() -{ -// Mutex::Autolock l(&mLock); - return mCameraRunning && mPreviewCallback != NULL; -} - -int QualcommCameraHardware::getParm( - const char *parm_str, const struct str_map *const parm_map) -{ - // Check if the parameter exists. - const char *str = mParameters.get(parm_str); - if (str == NULL) return NOT_FOUND; - - // Look up the parameter value. - return attr_lookup(parm_map, str); -} - -void QualcommCameraHardware::setEffect() -{ - int32_t value = getParm("effect", effect); - if (value != NOT_FOUND) { - native_set_parm(CAMERA_SET_PARM_EFFECT, sizeof(value), (void *)&value); - } -} - -void QualcommCameraHardware::setWhiteBalance() -{ - int32_t value = getParm("whitebalance", whitebalance); - if (value != NOT_FOUND) { - native_set_parm(CAMERA_SET_PARM_WB, sizeof(value), (void *)&value); - } -} - -void QualcommCameraHardware::setAntibanding() -{ - camera_antibanding_type value = - (camera_antibanding_type) getParm("antibanding", antibanding); - native_set_parm(CAMERA_SET_PARM_ANTIBANDING, sizeof(value), (void *)&value); -} - -QualcommCameraHardware::MemPool::MemPool(int buffer_size, int num_buffers, - int frame_size, - int frame_offset, - const char *name) : - mBufferSize(buffer_size), - mNumBuffers(num_buffers), - mFrameSize(frame_size), - mFrameOffset(frame_offset), - mBuffers(NULL), mName(name) -{ - // empty -} - -void QualcommCameraHardware::MemPool::completeInitialization() -{ - // If we do not know how big the frame will be, we wait to allocate - // the buffers describing the individual frames until we do know their - // size. - - if (mFrameSize > 0) { - mBuffers = new sp[mNumBuffers]; - for (int i = 0; i < mNumBuffers; i++) { - mBuffers[i] = new - MemoryBase(mHeap, - i * mBufferSize + mFrameOffset, - mFrameSize); - } - } -} - -QualcommCameraHardware::AshmemPool::AshmemPool(int buffer_size, int num_buffers, - int frame_size, - int frame_offset, - const char *name) : - QualcommCameraHardware::MemPool(buffer_size, - num_buffers, - frame_size, - frame_offset, - name) -{ - LOGV("constructing MemPool %s backed by ashmem: " - "%d frames @ %d uint8_ts, offset %d, " - "buffer size %d", - mName, - num_buffers, frame_size, frame_offset, buffer_size); - - int page_mask = getpagesize() - 1; - int ashmem_size = buffer_size * num_buffers; - ashmem_size += page_mask; - ashmem_size &= ~page_mask; - - mHeap = new MemoryHeapBase(ashmem_size); - - completeInitialization(); -} - -static bool register_buf(int camfd, - int size, - int pmempreviewfd, - uint32_t offset, - uint8_t *buf, - int pmem_type, - bool register_buffer = true); - -QualcommCameraHardware::PmemPool::PmemPool(const char *pmem_pool, - int camera_control_fd, - int pmem_type, - int buffer_size, int num_buffers, - int frame_size, - int frame_offset, - const char *name) : - QualcommCameraHardware::MemPool(buffer_size, - num_buffers, - frame_size, - frame_offset, - name), - mPmemType(pmem_type), - mCameraControlFd(dup(camera_control_fd)) -{ - LOGV("constructing MemPool %s backed by pmem pool %s: " - "%d frames @ %d bytes, offset %d, buffer size %d", - mName, - pmem_pool, num_buffers, frame_size, frame_offset, - buffer_size); - - LOGV("%s: duplicating control fd %d --> %d", - __FUNCTION__, - camera_control_fd, mCameraControlFd); - - // Make a new mmap'ed heap that can be shared across processes. - - mAlignedSize = clp2(buffer_size * num_buffers); - - sp masterHeap = - new MemoryHeapBase(pmem_pool, mAlignedSize, 0); - sp pmemHeap = new MemoryHeapPmem(masterHeap, 0); - if (pmemHeap->getHeapID() >= 0) { - pmemHeap->slap(); - masterHeap.clear(); - mHeap = pmemHeap; - pmemHeap.clear(); - - mFd = mHeap->getHeapID(); - if (::ioctl(mFd, PMEM_GET_SIZE, &mSize)) { - LOGE("pmem pool %s ioctl(PMEM_GET_SIZE) error %s (%d)", - pmem_pool, - ::strerror(errno), errno); - mHeap.clear(); - return; - } - - LOGV("pmem pool %s ioctl(fd = %d, PMEM_GET_SIZE) is %ld", - pmem_pool, - mFd, - mSize.len); - - // Unregister preview buffers with the camera drivers. - for (int cnt = 0; cnt < num_buffers; ++cnt) { - register_buf(mCameraControlFd, - buffer_size, - mHeap->getHeapID(), - buffer_size * cnt, - (uint8_t *)mHeap->base() + buffer_size * cnt, - pmem_type); - } - - completeInitialization(); - } - else LOGE("pmem pool %s error: could not create master heap!", - pmem_pool); -} - -QualcommCameraHardware::PmemPool::~PmemPool() -{ - LOGV("%s: %s E", __FUNCTION__, mName); - // Unregister preview buffers with the camera drivers. - for (int cnt = 0; cnt < mNumBuffers; ++cnt) { - register_buf(mCameraControlFd, - mBufferSize, - mHeap->getHeapID(), - mBufferSize * cnt, - (uint8_t *)mHeap->base() + mBufferSize * cnt, - mPmemType, - false /* unregister */); - } - LOGV("destroying PmemPool %s: closing control fd %d", - mName, - mCameraControlFd); - close(mCameraControlFd); - LOGV("%s: %s X", __FUNCTION__, mName); -} - -QualcommCameraHardware::MemPool::~MemPool() -{ - LOGV("destroying MemPool %s", mName); - if (mFrameSize > 0) - delete [] mBuffers; - mHeap.clear(); - LOGV("destroying MemPool %s completed", mName); -} - -static bool register_buf(int camfd, - int size, - int pmempreviewfd, - uint32_t offset, - uint8_t *buf, - int pmem_type, - bool register_buffer) -{ - struct msm_pmem_info pmemBuf; - - pmemBuf.type = pmem_type; - pmemBuf.fd = pmempreviewfd; - pmemBuf.offset = offset; - pmemBuf.len = size; - pmemBuf.vaddr = buf; - pmemBuf.y_off = 0; - pmemBuf.cbcr_off = PAD_TO_WORD(size * 2 / 3); - pmemBuf.active = true; - - LOGV("register_buf: camfd = %d, reg = %d buffer = %p", - camfd, !register_buffer, buf); - if (ioctl(camfd, - register_buffer ? - MSM_CAM_IOCTL_REGISTER_PMEM : - MSM_CAM_IOCTL_UNREGISTER_PMEM, - &pmemBuf) < 0) { - LOGE("register_buf: MSM_CAM_IOCTL_(UN)REGISTER_PMEM fd %d error %s", - camfd, - strerror(errno)); - return false; - } - return true; -} - -status_t QualcommCameraHardware::MemPool::dump(int fd, const Vector& args) const -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - snprintf(buffer, 255, "QualcommCameraHardware::AshmemPool::dump\n"); - result.append(buffer); - if (mName) { - snprintf(buffer, 255, "mem pool name (%s)\n", mName); - result.append(buffer); - } - if (mHeap != 0) { - snprintf(buffer, 255, "heap base(%p), size(%d), flags(%d), device(%s)\n", - mHeap->getBase(), mHeap->getSize(), - mHeap->getFlags(), mHeap->getDevice()); - result.append(buffer); - } - snprintf(buffer, 255, "buffer size (%d), number of buffers (%d)," - " frame size(%d), and frame offset(%d)\n", - mBufferSize, mNumBuffers, mFrameSize, mFrameOffset); - result.append(buffer); - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -static void receive_camframe_callback(struct msm_frame *frame) -{ - sp obj = QualcommCameraHardware::getInstance(); - if (obj != 0) { - obj->receivePreviewFrame(frame); - } -} - -static void receive_jpeg_fragment_callback(uint8_t *buff_ptr, uint32_t buff_size) -{ - LOGV("receive_jpeg_fragment_callback E"); - sp obj = QualcommCameraHardware::getInstance(); - if (obj != 0) { - obj->receiveJpegPictureFragment(buff_ptr, buff_size); - } - LOGV("receive_jpeg_fragment_callback X"); -} - -static void receive_jpeg_callback(jpeg_event_t status) -{ - LOGV("receive_jpeg_callback E (completion status %d)", status); - if (status == JPEG_EVENT_DONE) { - sp obj = QualcommCameraHardware::getInstance(); - if (obj != 0) { - obj->receiveJpegPicture(); - } - } - LOGV("receive_jpeg_callback X"); -} - -}; // namespace android diff --git a/libcamera2/QualcommCameraHardware.h b/libcamera2/QualcommCameraHardware.h deleted file mode 100644 index a4fe43b..0000000 --- a/libcamera2/QualcommCameraHardware.h +++ /dev/null @@ -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 -#include -#include -#include - -extern "C" { -#include -#include -#include -} - -struct str_map { - const char *const desc; - int val; -}; - -namespace android { - -class QualcommCameraHardware : public CameraHardwareInterface { -public: - - virtual sp getPreviewHeap() const; - virtual sp getRawHeap() const; - - virtual status_t dump(int fd, const Vector& 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& 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 createInstance(); - static sp 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 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& args) const; - - int mBufferSize; - int mNumBuffers; - int mFrameSize; - int mFrameOffset; - sp mHeap; - sp *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 mPreviewHeap; - sp mThumbnailHeap; - sp mRawHeap; - sp 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 diff --git a/libcopybit/Android.mk b/libcopybit/Android.mk index f6a1b4b..36b1416 100644 --- a/libcopybit/Android.mk +++ b/libcopybit/Android.mk @@ -16,10 +16,27 @@ LOCAL_PATH:= $(call my-dir) # HAL module implemenation, not prelinked and stored in # hw/..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 diff --git a/libcopybit/copybit.c b/libcopybit/copybit.cpp similarity index 77% rename from libcopybit/copybit.c rename to libcopybit/copybit.cpp index 3565074..ba8531b 100644 --- a/libcopybit/copybit.c +++ b/libcopybit/copybit.cpp @@ -34,6 +34,20 @@ #include +#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 = ©bit_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: ©bit_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 ; icount ; 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(module); ctx->device.common.close = close_copybit; ctx->device.set_parameter = set_parameter_copybit; ctx->device.get = get; diff --git a/libgralloc-qsd8k/Android.mk b/libgralloc-qsd8k/Android.mk new file mode 100644 index 0000000..d5ffa42 --- /dev/null +++ b/libgralloc-qsd8k/Android.mk @@ -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/..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) diff --git a/libgralloc-qsd8k/allocator.cpp b/libgralloc-qsd8k/allocator.cpp new file mode 100644 index 0000000..4dad6a1 --- /dev/null +++ b/libgralloc-qsd8k/allocator.cpp @@ -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 + +#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; +} diff --git a/libgralloc-qsd8k/allocator.h b/libgralloc-qsd8k/allocator.h new file mode 100644 index 0000000..b0d89e9 --- /dev/null +++ b/libgralloc-qsd8k/allocator.h @@ -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 +#include + +#include "gr.h" + +// ---------------------------------------------------------------------------- + +/* + * A simple templatized doubly linked-list implementation + */ + +template +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 mList; + size_t mHeapSize; +}; + +#endif /* GRALLOC_ALLOCATOR_H_ */ diff --git a/libgralloc-qsd8k/framebuffer.cpp b/libgralloc-qsd8k/framebuffer.cpp new file mode 100644 index 0000000..797982f --- /dev/null +++ b/libgralloc-qsd8k/framebuffer.cpp @@ -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 + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#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( + 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(buffer); + private_module_t* m = reinterpret_cast( + dev->common.module); + + if (m->currentBuffer) { + m->base.unlock(&m->base, m->currentBuffer); + m->currentBuffer = 0; + } + + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { + + m->base.lock(&m->base, buffer, + private_module_t::PRIV_USAGE_LOCKED_FOR_POST, + 0, 0, m->info.xres, m->info.yres, NULL); + + 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(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(dev->device.flags) = 0; + const_cast(dev->device.width) = m->info.xres; + const_cast(dev->device.height) = m->info.yres; + const_cast(dev->device.stride) = stride; + const_cast(dev->device.format) = HAL_PIXEL_FORMAT_RGB_565; + const_cast(dev->device.xdpi) = m->xdpi; + const_cast(dev->device.ydpi) = m->ydpi; + const_cast(dev->device.fps) = m->fps; + const_cast(dev->device.minSwapInterval) = 1; + const_cast(dev->device.maxSwapInterval) = 1; + + 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); +} diff --git a/libgralloc-qsd8k/gr.h b/libgralloc-qsd8k/gr.h new file mode 100644 index 0000000..1775bfa --- /dev/null +++ b/libgralloc-qsd8k/gr.h @@ -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 +#ifdef HAVE_ANDROID_OS // just want PAGE_SIZE define +# include +#else +# include +#endif +#include +#include +#include +#include +#include + +#include + +/*****************************************************************************/ + +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_ */ diff --git a/libgralloc-qsd8k/gralloc.cpp b/libgralloc-qsd8k/gralloc.cpp new file mode 100644 index 0000000..45746ef --- /dev/null +++ b/libgralloc-qsd8k/gralloc.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "gralloc_priv.h" +#include "allocator.h" + +#if HAVE_ANDROID_OS +#include +#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( + 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<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 ; ibufferMask |= (1LU<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( + 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, ®ion) < 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, ®ion); + 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( + 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( + 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(handle); + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { + // free this buffer + private_module_t* m = reinterpret_cast( + 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<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( + dev->common.module); + terminateBuffer(module, const_cast(hnd)); + } + + close(hnd->fd); + delete hnd; + return 0; +} + +/*****************************************************************************/ + +static int gralloc_close(struct hw_device_t *dev) +{ + gralloc_context_t* ctx = reinterpret_cast(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(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; +} diff --git a/libgralloc-qsd8k/gralloc_priv.h b/libgralloc-qsd8k/gralloc_priv.h new file mode 100644 index 0000000..534b4c0 --- /dev/null +++ b/libgralloc-qsd8k/gralloc_priv.h @@ -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 +#include +#include +#include +#include +#include +#include + +#include + +#include + +/*****************************************************************************/ + +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_ */ diff --git a/libgralloc-qsd8k/mapper.cpp b/libgralloc-qsd8k/mapper.cpp new file mode 100644 index 0000000..8c199b3 --- /dev/null +++ b/libgralloc-qsd8k/mapper.cpp @@ -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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#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 +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; +} From 44311757be4494ad601b6249d3722c71ffb17777 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 12 Jan 2010 15:19:05 -0800 Subject: [PATCH 2/2] android-2.1_r1 snapshot --- libcopybit/copybit.cpp | 8 +++++ libgralloc-qsd8k/framebuffer.cpp | 54 +++++++++++++++++++++----------- libgralloc-qsd8k/gralloc.cpp | 36 ++++++++++----------- libgralloc-qsd8k/gralloc_priv.h | 6 ++-- 4 files changed, 63 insertions(+), 41 deletions(-) diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp index ba8531b..fb605fe 100644 --- a/libcopybit/copybit.cpp +++ b/libcopybit/copybit.cpp @@ -42,8 +42,10 @@ #if defined(COPYBIT_MSM7K) #define MAX_SCALE_FACTOR (4) +#define MAX_DIMENSION (4096) #elif defined(COPYBIT_QSD8K) #define MAX_SCALE_FACTOR (8) +#define MAX_DIMENSION (2048) #else #error "Unsupported MDP version" #endif @@ -366,6 +368,12 @@ static int stretch_copybit( return -EINVAL; } + if (src->w > MAX_DIMENSION || src->h > MAX_DIMENSION) + return -EINVAL; + + if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION) + 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; diff --git a/libgralloc-qsd8k/framebuffer.cpp b/libgralloc-qsd8k/framebuffer.cpp index 797982f..11b303a 100644 --- a/libgralloc-qsd8k/framebuffer.cpp +++ b/libgralloc-qsd8k/framebuffer.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -59,7 +60,8 @@ struct fb_context_t { /*****************************************************************************/ static void -msm_copy_buffer(buffer_handle_t handle, int fd, int width, int height, +msm_copy_buffer(buffer_handle_t handle, int fd, + int width, int height, int format, int x, int y, int w, int h); static int fb_setSwapInterval(struct framebuffer_device_t* dev, @@ -120,9 +122,6 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) 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; @@ -138,8 +137,9 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) //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, + msm_copy_buffer( + m->framebuffer, m->framebuffer->fd, + m->info.xres, m->info.yres, m->fbFormat, m->info.xoffset, m->info.yoffset, m->info.width, m->info.height); @@ -152,7 +152,7 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) static int fb_compositionComplete(struct framebuffer_device_t* dev) { - // STOPSHIP: Properly implement composition complete callback + // TODO: Properly implement composition complete callback glFinish(); return 0; @@ -199,19 +199,35 @@ int mapFrameBufferLocked(struct private_module_t* module) info.yoffset = 0; info.activate = FB_ACTIVATE_NOW; + /* Interpretation of offset for color fields: All offsets are from the right, + * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you + * can use the offset as right argument to <<). A pixel afterwards is a bit + * stream and is written to video memory as that unmodified. This implies + * big-endian byte order if bits_per_pixel is greater than 8. + */ + /* - * Explicitly request 5/6/5 + * Explicitly request RGBA_8888 */ - 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.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; + /* * Request NUM_BUFFERS screens (at lest 2 for page flipping) */ @@ -322,7 +338,6 @@ int mapFrameBufferLocked(struct private_module_t* module) return -errno; } module->framebuffer->base = intptr_t(vaddr); - module->framebuffer->phys = intptr_t(finfo.smem_start); memset(vaddr, 0, fbSize); return 0; } @@ -378,7 +393,7 @@ int fb_device_open(hw_module_t const* module, const char* name, const_cast(dev->device.width) = m->info.xres; const_cast(dev->device.height) = m->info.yres; const_cast(dev->device.stride) = stride; - const_cast(dev->device.format) = HAL_PIXEL_FORMAT_RGB_565; + const_cast(dev->device.format) = m->fbFormat; const_cast(dev->device.xdpi) = m->xdpi; const_cast(dev->device.ydpi) = m->ydpi; const_cast(dev->device.fps) = m->fps; @@ -400,7 +415,8 @@ int fb_device_open(hw_module_t const* module, const char* name, /* Copy a pmem buffer to the framebuffer */ static void -msm_copy_buffer(buffer_handle_t handle, int fd, int width, int height, +msm_copy_buffer(buffer_handle_t handle, int fd, + int width, int height, int format, int x, int y, int w, int h) { struct { @@ -425,7 +441,7 @@ msm_copy_buffer(buffer_handle_t handle, int fd, int width, int height, 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.dst.format = format; blit.req.src_rect.x = blit.req.dst_rect.x = x; blit.req.src_rect.y = blit.req.dst_rect.y = y; diff --git a/libgralloc-qsd8k/gralloc.cpp b/libgralloc-qsd8k/gralloc.cpp index 45746ef..9887057 100644 --- a/libgralloc-qsd8k/gralloc.cpp +++ b/libgralloc-qsd8k/gralloc.cpp @@ -104,6 +104,7 @@ struct private_module_t HAL_MODULE_INFO_SYM = { perform: gralloc_perform, }, framebuffer: 0, + fbFormat: 0, flags: 0, numBuffers: 0, bufferMask: 0, @@ -111,7 +112,6 @@ struct private_module_t HAL_MODULE_INFO_SYM = { currentBuffer: 0, pmem_master: -1, pmem_master_base: 0, - master_phys: 0 }; /*****************************************************************************/ @@ -165,7 +165,6 @@ static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev, hnd->base = vaddr; hnd->offset = vaddr - intptr_t(m->framebuffer->base); - hnd->phys = intptr_t(m->framebuffer->phys) + hnd->offset; *pHandle = hnd; return 0; @@ -205,15 +204,6 @@ static int init_pmem_area_locked(private_module_t* m) 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, ®ion); - 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; @@ -289,9 +279,16 @@ try_ashmem: err = -ENOMEM; } else { struct pmem_region sub = { offset, size }; - + int openFlags = O_RDWR | O_SYNC; + uint32_t uread = usage & GRALLOC_USAGE_SW_READ_MASK; + uint32_t uwrite = usage & GRALLOC_USAGE_SW_WRITE_MASK; + if (uread == GRALLOC_USAGE_SW_READ_OFTEN || + uwrite == GRALLOC_USAGE_SW_WRITE_OFTEN) { + openFlags &= ~O_SYNC; + } + // now create the "sub-heap" - fd = open("/dev/pmem", O_RDWR, 0); + fd = open("/dev/pmem", openFlags, 0); err = fd < 0 ? fd : 0; // and connect to it @@ -307,8 +304,11 @@ try_ashmem: close(fd); sAllocator.deallocate(offset); fd = -1; + } else { + memset((char*)base + offset, 0, size); + // clean and invalidate the new allocation + cacheflush(intptr_t(base) + offset, size, 0); } - memset((char*)base + offset, 0, size); //LOGD_IF(!err, "allocating pmem size=%d, offset=%d", size, offset); } } else { @@ -328,11 +328,6 @@ try_ashmem: 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( - dev->common.module); - hnd->phys = m->master_phys + offset; - } *pHandle = hnd; } @@ -391,6 +386,9 @@ static int gralloc_alloc(alloc_device_t* dev, size = alignedw * alignedh * bpp; } + if ((ssize_t)size <= 0) + return -EINVAL; + int err; if (usage & GRALLOC_USAGE_HW_FB) { err = gralloc_alloc_framebuffer(dev, size, usage, pHandle); diff --git a/libgralloc-qsd8k/gralloc_priv.h b/libgralloc-qsd8k/gralloc_priv.h index 534b4c0..d74c1f2 100644 --- a/libgralloc-qsd8k/gralloc_priv.h +++ b/libgralloc-qsd8k/gralloc_priv.h @@ -38,6 +38,7 @@ struct private_module_t { gralloc_module_t base; struct private_handle_t* framebuffer; + uint32_t fbFormat; uint32_t flags; uint32_t numBuffers; uint32_t bufferMask; @@ -45,7 +46,6 @@ struct private_module_t { 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; @@ -92,7 +92,7 @@ struct private_handle_t { 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 gpuaddr; // The gpu address mapped into the mmu. If using ashmem, set to 0 They don't care int pid; #ifdef __cplusplus @@ -102,7 +102,7 @@ struct private_handle_t { 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()) + base(0), lockState(0), writeOwner(0), gpuaddr(0), pid(getpid()) { version = sizeof(native_handle); numInts = sNumInts;