Merge git://codeaurora.org/platform/hardware/qcom/display.git ics into ics and resolve conflicts

Change-Id: I3acb5e963763821d2b547cf3c9390754dc42c12f
This commit is contained in:
toastcfh 2011-12-18 19:45:23 -05:00
commit b67994677f
29 changed files with 2414 additions and 327 deletions

View File

@ -2,5 +2,6 @@
ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
display-hals := libhwcomposer liboverlay libgralloc libcopybit
display-hals += libqcomui
include $(call all-named-subdir-makefiles,$(display-hals))
endif

View File

@ -21,8 +21,8 @@ ifeq ($(TARGET_USES_C2D_COMPOSITION),true)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libdl
LOCAL_SRC_FILES := copybit_c2d.cpp
LOCAL_SHARED_LIBRARIES := liblog libdl libcutils
LOCAL_SRC_FILES := copybit_c2d.cpp software_converter.cpp
LOCAL_MODULE := copybit.$(TARGET_BOARD_PLATFORM)
LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc
LOCAL_CFLAGS += -DCOPYBIT_Z180=1 -DC2D_SUPPORT_DISPLAY=1

View File

@ -387,9 +387,8 @@ static int stretch_copybit(
if(src->format == HAL_PIXEL_FORMAT_YV12) {
if(0 == convertYV12toYCrCb420SP(src)){
//if inplace conversion,just convert and return
if(src->base == dst->base)
return status;
(const_cast<copybit_image_t *>(src))->format =
HAL_PIXEL_FORMAT_YCrCb_420_SP;
}
else{
LOGE("Error copybit conversion from yv12 failed");

View File

@ -65,7 +65,11 @@ enum {
COPYBIT_BLUR = 5,
/* Informs the copybit that the source and destination contains
premultiplied alpha */
COPYBIT_PREMULTIPLIED_ALPHA = 6
COPYBIT_PREMULTIPLIED_ALPHA = 6,
/* FB width */
COPYBIT_FRAMEBUFFER_WIDTH = 7,
/* FB height */
COPYBIT_FRAMEBUFFER_HEIGHT = 8,
};
/* values for copybit_set_parameter(COPYBIT_TRANSFORM) */

File diff suppressed because it is too large Load Diff

57
libcopybit/copybit_priv.h Normal file
View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <copybit.h>
struct copybit_iterator : public copybit_region_t {
copybit_iterator(const copybit_rect_t& rect) {
mRect = rect;
mCount = 1;
this->next = iterate;
}
private:
static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
if (!self || !rect) {
return 0;
}
copybit_iterator const* me = static_cast<copybit_iterator const*>(self);
if (me->mCount) {
rect->l = me->mRect.l;
rect->t = me->mRect.t;
rect->r = me->mRect.r;
rect->b = me->mRect.b;
me->mCount--;
return 1;
}
return 0;
}
copybit_rect_t mRect;
mutable int mCount;
};

View File

@ -32,7 +32,6 @@
#include <stdlib.h>
#include <errno.h>
#include "software_converter.h"
#include "gralloc_priv.h"
/** Convert YV12 to YCrCb_420_SP */
int convertYV12toYCrCb420SP(const copybit_image_t *src)
@ -166,3 +165,141 @@ int convertYV12toYCrCb420SP(const copybit_image_t *src)
free(tempBuf);
return 0;
}
struct copyInfo{
int width;
int height;
int src_stride;
int dst_stride;
int src_plane1_offset;
int src_plane2_offset;
int dst_plane1_offset;
int dst_plane2_offset;
};
/* Internal function to do the actual copy of source to destination */
static int copy_source_to_destination(const int src_base, const int dst_base,
copyInfo& info)
{
if (!src_base || !dst_base) {
LOGE("%s: invalid memory src_base = 0x%x dst_base=0x%x",
__FUNCTION__, src_base, dst_base);
return COPYBIT_FAILURE;
}
int width = info.width;
int height = info.height;
unsigned char *src = (unsigned char*)src_base;
unsigned char *dst = (unsigned char*)dst_base;
// Copy the luma
for (int i = 0; i < height; i++) {
memcpy(dst, src, width);
src += info.src_stride;
dst += info.dst_stride;
}
// Copy plane 1
src = (unsigned char*)(src_base + info.src_plane1_offset);
dst = (unsigned char*)(dst_base + info.dst_plane1_offset);
width = width/2;
height = height/2;
for (int i = 0; i < height; i++) {
memcpy(dst, src, info.src_stride);
src += info.src_stride;
dst += info.dst_stride;
}
return 0;
}
/*
* Function to convert the c2d format into an equivalent Android format
*
* @param: source buffer handle
* @param: destination image
*
* @return: return status
*/
int convert_yuv_c2d_to_yuv_android(private_handle_t *hnd,
struct copybit_image_t const *rhs)
{
LOGD("Enter %s", __FUNCTION__);
if (!hnd || !rhs) {
LOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs);
return COPYBIT_FAILURE;
}
int ret = COPYBIT_SUCCESS;
private_handle_t *dst_hnd = (private_handle_t *)rhs->handle;
copyInfo info;
info.width = rhs->w;
info.height = rhs->h;
info.src_stride = ALIGN(info.width, 32);
info.dst_stride = ALIGN(info.width, 16);
switch(rhs->format) {
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
info.src_plane1_offset = info.src_stride*info.height;
info.dst_plane1_offset = info.dst_stride*info.height;
} break;
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: {
// Chroma is 2K aligned for the NV12 encodeable format.
info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048);
info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048);
} break;
default:
LOGE("%s: unsupported format (format=0x%x)", __FUNCTION__,
rhs->format);
return COPYBIT_FAILURE;
}
ret = copy_source_to_destination(hnd->base, dst_hnd->base, info);
return ret;
}
/*
* Function to convert the Android format into an equivalent C2D format
*
* @param: source buffer handle
* @param: destination image
*
* @return: return status
*/
int convert_yuv_android_to_yuv_c2d(private_handle_t *hnd,
struct copybit_image_t const *rhs)
{
if (!hnd || !rhs) {
LOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs);
return COPYBIT_FAILURE;
}
int ret = COPYBIT_SUCCESS;
private_handle_t *dst_hnd = (private_handle_t *)rhs->handle;
copyInfo info;
info.width = rhs->w;
info.height = rhs->h;
info.src_stride = ALIGN(info.width, 16);
info.dst_stride = ALIGN(info.width, 32);
switch(rhs->format) {
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
info.src_plane1_offset = info.src_stride*info.height;
info.dst_plane1_offset = info.dst_stride*info.height;
} break;
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: {
// Chroma is 2K aligned for the NV12 encodeable format.
info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048);
info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048);
} break;
default:
LOGE("%s: unsupported format (format=0x%x)", __FUNCTION__,
rhs->format);
return -1;
}
ret = copy_source_to_destination(hnd->base, dst_hnd->base, info);
return ret;
}

View File

@ -30,9 +30,36 @@
#include <copybit.h>
#include "gralloc_priv.h"
#define COPYBIT_SUCCESS 0
#define COPYBIT_FAILURE -1
inline unsigned int ALIGN(unsigned int x, unsigned int align) {
return (x + align-1) & ~(align-1);
}
int convertYV12toYCrCb420SP(const copybit_image_t *src);
/*
* Function to convert the c2d format into an equivalent Android format
*
* @param: source buffer handle
* @param: destination image
*
* @return: return status
*/
int convert_yuv_c2d_to_yuv_android(private_handle_t *hnd,
struct copybit_image_t const *rhs);
/*
* Function to convert the Android format into an equivalent C2D format
*
* @param: source buffer handle
* @param: destination image
*
* @return: return status
*/
int convert_yuv_android_to_yuv_c2d(private_handle_t *hnd,
struct copybit_image_t const *rhs);

15
libgenlock/Android.mk Normal file
View File

@ -0,0 +1,15 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_SHARED_LIBRARIES := liblog libcutils
LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc
LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_SRC_FILES := genlock.cpp
LOCAL_CFLAGS:= -DLOG_TAG=\"libgenlock\"
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libgenlock
include $(BUILD_SHARED_LIBRARY)

323
libgenlock/genlock.cpp Normal file
View File

@ -0,0 +1,323 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cutils/log.h>
#include <cutils/native_handle.h>
#include <gralloc_priv.h>
#include <linux/genlock.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "genlock.h"
#define GENLOCK_DEVICE "/dev/genlock"
#ifndef USE_GENLOCK
#define USE_GENLOCK
#endif
namespace {
/* Internal function to map the userspace locks to the kernel lock types */
int get_kernel_lock_type(genlock_lock_type lockType)
{
int kLockType = 0;
// If the user sets both a read and write lock, higher preference is
// given to the write lock.
if (lockType & GENLOCK_WRITE_LOCK) {
kLockType = GENLOCK_WRLOCK;
} else if (lockType & GENLOCK_READ_LOCK) {
kLockType = GENLOCK_RDLOCK;
} else {
LOGE("%s: invalid lockType (lockType = %d)", __FUNCTION__, lockType);
return -1;
}
return kLockType;
}
/* Internal function to perform the actual lock/unlock operations */
genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle,
int lockType, int timeout)
{
if (private_handle_t::validate(buffer_handle)) {
LOGE("%s: handle is invalid", __FUNCTION__);
return GENLOCK_FAILURE;
}
private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
if (hnd->genlockPrivFd < 0) {
LOGE("%s: the lock has not been created, or has not been attached",
__FUNCTION__);
return GENLOCK_FAILURE;
}
genlock_lock lock;
lock.op = lockType;
lock.flags = 0;
lock.timeout = timeout;
lock.fd = hnd->genlockHandle;
if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_LOCK, &lock)) {
LOGE("%s: GENLOCK_IOC_LOCK failed (lockType0x%x, err=%s fd=%d)", __FUNCTION__,
lockType, strerror(errno), hnd->fd);
if (ETIMEDOUT == errno)
return GENLOCK_TIMEDOUT;
return GENLOCK_FAILURE;
}
return GENLOCK_NO_ERROR;
}
/* Internal function to close the fd and release the handle */
void close_genlock_fd_and_handle(int& fd, int& handle)
{
if (fd >=0 ) {
close(fd);
fd = -1;
}
if (handle >= 0) {
close(handle);
handle = -1;
}
}
}
/*
* Create a genlock lock. The genlock lock file descriptor and the lock
* handle are stored in the buffer_handle.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
{
genlock_status_t ret = GENLOCK_NO_ERROR;
if (private_handle_t::validate(buffer_handle)) {
LOGE("%s: handle is invalid", __FUNCTION__);
return GENLOCK_FAILURE;
}
private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
#ifdef USE_GENLOCK
// Open the genlock device
int fd = open(GENLOCK_DEVICE, O_RDWR);
if (fd < 0) {
LOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
strerror(errno));
return GENLOCK_FAILURE;
}
// Create a new lock
genlock_lock lock;
if (ioctl(fd, GENLOCK_IOC_NEW, NULL)) {
LOGE("%s: GENLOCK_IOC_NEW failed (error=%s)", __FUNCTION__,
strerror(errno));
close_genlock_fd_and_handle(fd, lock.fd);
ret = GENLOCK_FAILURE;
}
// Export the lock for other processes to be able to use it.
if (GENLOCK_FAILURE != ret) {
if (ioctl(fd, GENLOCK_IOC_EXPORT, &lock)) {
LOGE("%s: GENLOCK_IOC_EXPORT failed (error=%s)", __FUNCTION__,
strerror(errno));
close_genlock_fd_and_handle(fd, lock.fd);
ret = GENLOCK_FAILURE;
}
}
// Store the lock params in the handle.
hnd->genlockPrivFd = fd;
hnd->genlockHandle = lock.fd;
#else
hnd->genlockHandle = 0;
#endif
return ret;
}
/*
* Release a genlock lock associated with the handle.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_release_lock(native_handle_t *buffer_handle)
{
genlock_status_t ret = GENLOCK_NO_ERROR;
#ifdef USE_GENLOCK
if (private_handle_t::validate(buffer_handle)) {
LOGE("%s: handle is invalid", __FUNCTION__);
return GENLOCK_FAILURE;
}
private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
if (hnd->genlockPrivFd < 0) {
LOGE("%s: the lock is invalid", __FUNCTION__);
return GENLOCK_FAILURE;
}
if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_RELEASE, NULL)) {
LOGE("%s: GENLOCK_IOC_RELEASE failed (err=%s)", __FUNCTION__,
strerror(errno));
ret = GENLOCK_FAILURE;
}
// Close the fd and reset the parameters.
close_genlock_fd_and_handle(hnd->genlockPrivFd, hnd->genlockHandle);
#endif
return ret;
}
/*
* Attach a lock to the buffer handle passed via an IPC.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle)
{
genlock_status_t ret = GENLOCK_NO_ERROR;
#ifdef USE_GENLOCK
if (private_handle_t::validate(buffer_handle)) {
LOGE("%s: handle is invalid", __FUNCTION__);
return GENLOCK_FAILURE;
}
// Open the genlock device
int fd = open(GENLOCK_DEVICE, O_RDWR);
if (fd < 0) {
LOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
strerror(errno));
return GENLOCK_FAILURE;
}
// Attach the local handle to an existing lock
private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
genlock_lock lock;
lock.fd = hnd->genlockHandle;
if (ioctl(fd, GENLOCK_IOC_ATTACH, &lock)) {
LOGE("%s: GENLOCK_IOC_ATTACH failed (err=%s)", __FUNCTION__,
strerror(errno));
close_genlock_fd_and_handle(fd, lock.fd);
ret = GENLOCK_FAILURE;
}
// Store the relavant information in the handle
hnd->genlockPrivFd = fd;
#endif
return ret;
}
/*
* Lock the buffer specified by the buffer handle. The lock held by the buffer
* is specified by the lockType. This function will block if a write lock is
* requested on the buffer which has previously been locked for a read or write
* operation. A buffer can be locked by multiple clients for read. An optional
* timeout value can be specified. By default, there is no timeout.
*
* @param: handle of the buffer
* @param: type of lock to be acquired by the buffer.
* @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value.
* @return error status.
*/
genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
genlock_lock_type_t lockType,
int timeout)
{
genlock_status_t ret = GENLOCK_NO_ERROR;
#ifdef USE_GENLOCK
// Translate the locktype
int kLockType = get_kernel_lock_type(lockType);
if (-1 == kLockType) {
LOGE("%s: invalid lockType", __FUNCTION__);
return GENLOCK_FAILURE;
}
if (0 == timeout) {
LOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
}
// Call the private function to perform the lock operation specified.
ret = perform_lock_unlock_operation(buffer_handle, kLockType, timeout);
#endif
return ret;
}
/*
* Unlocks a buffer that has previously been locked by the client.
*
* @param: handle of the buffer to be unlocked.
* @return: error status.
*/
genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle)
{
genlock_status_t ret = GENLOCK_NO_ERROR;
#ifdef USE_GENLOCK
// Do the unlock operation by setting the unlock flag. Timeout is always
// 0 in this case.
ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0);
#endif
return ret;
}
/*
* Blocks the calling process until the lock held on the handle is unlocked.
*
* @param: handle of the buffer
* @param: timeout value for the wait.
* return: error status.
*/
genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout) {
#ifdef USE_GENLOCK
if (private_handle_t::validate(buffer_handle)) {
LOGE("%s: handle is invalid", __FUNCTION__);
return GENLOCK_FAILURE;
}
private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
if (hnd->genlockPrivFd < 0) {
LOGE("%s: the lock is invalid", __FUNCTION__);
return GENLOCK_FAILURE;
}
if (0 == timeout)
LOGW("%s: timeout = 0", __FUNCTION__);
genlock_lock lock;
lock.fd = hnd->genlockHandle;
lock.timeout = timeout;
if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_WAIT, &lock)) {
LOGE("%s: GENLOCK_IOC_WAIT failed (err=%s)", __FUNCTION__, strerror(errno));
return GENLOCK_FAILURE;
}
#endif
return GENLOCK_NO_ERROR;
}

118
libgenlock/genlock.h Normal file
View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef INCLUDE_LIBGENLOCK
#define INCLUDE_LIBGENLOCK
#include <cutils/native_handle.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Genlock lock types */
typedef enum genlock_lock_type{
GENLOCK_READ_LOCK = 1<<0, // Read lock
GENLOCK_WRITE_LOCK = 1<<1, // Write lock
}genlock_lock_type_t;
/* Genlock return values */
typedef enum genlock_status{
GENLOCK_NO_ERROR = 0,
GENLOCK_TIMEDOUT,
GENLOCK_FAILURE,
} genlock_status_t;
/* Genlock defines */
#define GENLOCK_MAX_TIMEOUT 1000 // Max 1s timeout
/*
* Create a genlock lock. The genlock lock file descriptor and the lock
* handle are stored in the buffer_handle.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_create_lock(native_handle_t *buffer_handle);
/*
* Release a genlock lock associated with the handle.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_release_lock(native_handle_t *buffer_handle);
/*
* Attach a lock to the buffer handle passed via an IPC.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle);
/*
* Lock the buffer specified by the buffer handle. The lock held by the buffer
* is specified by the lockType. This function will block if a write lock is
* requested on the buffer which has previously been locked for a read or write
* operation. A buffer can be locked by multiple clients for read. An optional
* timeout value can be specified. By default, there is no timeout.
*
* @param: handle of the buffer
* @param: type of lock to be acquired by the buffer.
* @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value.
* @return error status.
*/
genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
genlock_lock_type_t lockType,
int timeout);
/*
* Unlocks a buffer that has previously been locked by the client.
*
* @param: handle of the buffer to be unlocked.
* @return: error status.
*/
genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle);
/*
* Blocks the calling process until the lock held on the handle is unlocked.
*
* @param: handle of the buffer
* @param: timeout value for the wait.
* return: error status.
*/
genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout);
#ifdef __cplusplus
}
#endif
#endif

7
libgralloc/Android.mk Normal file → Executable file
View File

@ -21,7 +21,8 @@ include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libcutils libGLESv1_CM libutils libmemalloc
LOCAL_SHARED_LIBRARIES += libgenlock
LOCAL_C_INCLUDES += hardware/qcom/display/libgenlock
LOCAL_SRC_FILES := framebuffer.cpp \
gpu.cpp \
gralloc.cpp \
@ -41,8 +42,8 @@ ifeq ($(TARGET_HAVE_HDMI_OUT),true)
LOCAL_SHARED_LIBRARIES += liboverlay
endif
ifeq ($(TARGET_USES_SF_BYPASS),true)
LOCAL_CFLAGS += -DSF_BYPASS
ifeq ($(TARGET_HAVE_BYPASS),true)
LOCAL_CFLAGS += -DCOMPOSITION_BYPASS
endif
ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true)

View File

@ -89,6 +89,7 @@ int IonController::allocate(alloc_data& data, int usage,
{
int ionFlags = 0;
int ret;
bool noncontig = false;
//System heap cannot be uncached
if (usage & GRALLOC_USAGE_PRIVATE_UNCACHED &&
@ -106,8 +107,10 @@ int IonController::allocate(alloc_data& data, int usage,
if(usage & GRALLOC_USAGE_PRIVATE_EBI_HEAP)
ionFlags |= 1 << ION_HEAP_EBI_ID;
if(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP)
if(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP) {
ionFlags |= 1 << ION_HEAP_SYSTEM_ID;
noncontig = true;
}
// if no flags are set, default to
// EBI heap, so that bypass can work
@ -125,11 +128,15 @@ int IonController::allocate(alloc_data& data, int usage,
{
LOGW("Falling back to system heap");
data.flags = 1 << ION_HEAP_SYSTEM_ID;
noncontig = true;
ret = mIonAlloc->alloc_buffer(data);
}
if(ret >= 0 )
if(ret >= 0 ) {
data.allocType = private_handle_t::PRIV_FLAGS_USES_ION;
if(noncontig)
data.allocType |= private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM;
}
return ret;
@ -166,6 +173,8 @@ int PmemKernelController::allocate(alloc_data& data, int usage,
{
int ret = 0;
bool adspFallback = false;
if (!(usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP))
adspFallback = true;
// Try SMI first
if ((usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP) ||
@ -181,8 +190,8 @@ int PmemKernelController::allocate(alloc_data& data, int usage,
if(ret >= 0)
return ret;
else {
adspFallback = true;
LOGW("Allocation from SMI failed, trying ADSP");
if(adspFallback)
LOGW("Allocation from SMI failed, trying ADSP");
}
}
}
@ -252,8 +261,10 @@ int PmemAshmemController::allocate(alloc_data& data, int usage,
if(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP) {
ret = mAshmemAlloc->alloc_buffer(data);
if(ret >= 0)
if(ret >= 0) {
data.allocType = private_handle_t::PRIV_FLAGS_USES_ASHMEM;
data.allocType |= private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM;
}
return ret;
}
@ -269,8 +280,10 @@ int PmemAshmemController::allocate(alloc_data& data, int usage,
} else if(ret < 0 && canFallback(compositionType, usage, false)) {
LOGW("Falling back to ashmem");
ret = mAshmemAlloc->alloc_buffer(data);
if(ret >= 0)
if(ret >= 0) {
data.allocType = private_handle_t::PRIV_FLAGS_USES_ASHMEM;
data.allocType |= private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM;
}
}
return ret;

View File

@ -103,7 +103,7 @@ int AshmemAlloc::map_buffer(void **pBase, size_t size, int offset, int fd)
return err;
base = mmap(0, size, PROT_READ| PROT_WRITE,
MAP_SHARED, fd, 0);
MAP_SHARED|MAP_POPULATE, fd, 0);
*pBase = base;
if(base == MAP_FAILED) {
LOGD("%s: Failed to map memory in the client: %s",

View File

@ -319,7 +319,7 @@ static void *disp_loop(void *ptr)
pthread_mutex_lock(&(m->qlock));
// wait (sleep) while display queue is empty;
if (m->disp.isEmpty()) {
while (m->disp.isEmpty()) {
pthread_cond_wait(&(m->qpost),&(m->qlock));
}
@ -347,6 +347,14 @@ static void *disp_loop(void *ptr)
LOGE("ERROR FBIOPUT_VSCREENINFO failed; frame not displayed");
}
#if defined COMPOSITION_BYPASS
//Signal so that we can close channels if we need to
pthread_mutex_lock(&m->bufferPostLock);
m->bufferPostDone = true;
pthread_cond_signal(&m->bufferPostCond);
pthread_mutex_unlock(&m->bufferPostLock);
#endif
#ifdef DEBUG_CALC_FPS
if (debug_fps_level > 0) calc_fps(ns2us(systemTime()));
#endif
@ -599,6 +607,34 @@ static int fb_orientationChanged(struct framebuffer_device_t* dev, int orientati
}
#endif
//Wait until framebuffer content is displayed.
//This is called in the context of threadLoop.
//Display loop wakes this up after display.
static int fb_waitForBufferPost(struct framebuffer_device_t* dev)
{
#if defined COMPOSITION_BYPASS
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
pthread_mutex_lock(&m->bufferPostLock);
while(m->bufferPostDone == false) {
pthread_cond_wait(&(m->bufferPostCond), &(m->bufferPostLock));
}
pthread_mutex_unlock(&m->bufferPostLock);
#endif
return 0;
}
static int fb_resetBufferPostStatus(struct framebuffer_device_t* dev)
{
#if defined COMPOSITION_BYPASS
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
pthread_mutex_lock(&m->bufferPostLock);
m->bufferPostDone = false;
pthread_mutex_unlock(&m->bufferPostLock);
#endif
return 0;
}
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
if (private_handle_t::validate(buffer) < 0)
@ -990,6 +1026,11 @@ int mapFrameBufferLocked(struct private_module_t* module)
pthread_t hdmiUIThread;
pthread_create(&hdmiUIThread, NULL, &hdmi_ui_loop, (void *) module);
#endif
#if defined COMPOSITION_BYPASS
pthread_mutex_init(&(module->bufferPostLock), NULL);
pthread_cond_init(&(module->bufferPostCond), NULL);
module->bufferPostDone = false;
#endif
return 0;
}
@ -1053,6 +1094,11 @@ int fb_device_open(hw_module_t const* module, const char* name,
dev->device.setActionSafeHeightRatio = fb_setActionSafeHeightRatio;
#endif
#if defined COMPOSITION_BYPASS
dev->device.waitForBufferPost = fb_waitForBufferPost;
dev->device.resetBufferPostStatus = fb_resetBufferPostStatus;
#endif
private_module_t* m = (private_module_t*)module;
status = mapFrameBuffer(m);
if (status >= 0) {

31
libgralloc/gpu.cpp Normal file → Executable file
View File

@ -21,16 +21,13 @@
#include <cutils/properties.h>
#include <sys/mman.h>
#include <genlock.h>
#include "gr.h"
#include "gpu.h"
#include "memalloc.h"
#include "alloc_controller.h"
static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
static const int QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03;
static const int QOMX_INTERLACE_FLAG = 0x49283654;
static const int QOMX_3D_VIDEO_FLAG = 0x23784238;
using namespace gralloc;
using android::sp;
@ -170,7 +167,6 @@ int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage,
hnd->offset = data.offset;
hnd->base = int(data.base) + data.offset;
hnd->lockState = private_handle_t::LOCK_STATE_MAPPED;
*pHandle = hnd;
}
@ -247,6 +243,7 @@ int gpu_context_t::alloc_impl(int w, int h, int format, int usage,
size = ALIGN( alignedw * alignedh, 8192);
size += ALIGN( alignedw * ALIGN(h/2, 32), 8192);
break;
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YV12:
@ -256,8 +253,14 @@ int gpu_context_t::alloc_impl(int w, int h, int format, int usage,
}
alignedw = ALIGN(w, 16);
alignedh = h;
size = alignedw*alignedh +
if (HAL_PIXEL_FORMAT_NV12_ENCODEABLE == colorFormat) {
// The encoder requires a 2K aligned chroma offset.
size = ALIGN(alignedw*alignedh, 2048) +
(ALIGN(alignedw/2, 16) * (alignedh/2))*2;
} else {
size = alignedw*alignedh +
(ALIGN(alignedw/2, 16) * (alignedh/2))*2;
}
size = ALIGN(size, 4096);
break;
@ -289,6 +292,13 @@ int gpu_context_t::alloc_impl(int w, int h, int format, int usage,
return err;
}
// Create a genlock lock for this buffer handle.
err = genlock_create_lock((native_handle_t*)(*pHandle));
if (err) {
LOGE("%s: genlock_create_lock failed", __FUNCTION__);
free_impl(reinterpret_cast<private_handle_t*>(pHandle));
return err;
}
*pStride = alignedw;
return 0;
}
@ -308,6 +318,13 @@ int gpu_context_t::free_impl(private_handle_t const* hnd) {
return err;
terminateBuffer(&m->base, const_cast<private_handle_t*>(hnd));
}
// Release the genlock
int err = genlock_release_lock((native_handle_t*)hnd);
if (err) {
LOGE("%s: genlock_release_lock failed", __FUNCTION__);
}
delete hnd;
return 0;
}

View File

@ -52,6 +52,13 @@ enum {
GRALLOC_USAGE_PRIVATE_ION = 0x00020000,
};
enum {
/* Gralloc perform enums
*/
GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER = 0x080000001,
};
enum {
GPU_COMPOSITION,
C2D_COMPOSITION,
@ -155,14 +162,7 @@ private:
enum {
/* OEM specific HAL formats */
//HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x100, // defined in hardware.h
//HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x101, // defined in hardware.h
HAL_PIXEL_FORMAT_YCbCr_422_P = 0x102,
HAL_PIXEL_FORMAT_YCbCr_420_P = 0x103,
//HAL_PIXEL_FORMAT_YCbCr_422_I = 0x104, // defined in hardware.h
HAL_PIXEL_FORMAT_YCbCr_420_I = 0x105,
HAL_PIXEL_FORMAT_CbYCrY_422_I = 0x106,
HAL_PIXEL_FORMAT_CbYCrY_420_I = 0x107,
HAL_PIXEL_FORMAT_NV12_ENCODEABLE = 0x102,
HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED = 0x108,
HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x109,
HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x10A,
@ -260,6 +260,11 @@ struct private_module_t {
pthread_mutex_t overlayLock;
pthread_cond_t overlayPost;
#endif
#ifdef COMPOSITION_BYPASS
pthread_mutex_t bufferPostLock;
pthread_cond_t bufferPostCond;
bool bufferPostDone;
#endif
};
/*****************************************************************************/
@ -278,16 +283,14 @@ struct private_handle_t {
PRIV_FLAGS_USES_ASHMEM = 0x00000010,
PRIV_FLAGS_NEEDS_FLUSH = 0x00000020,
PRIV_FLAGS_DO_NOT_FLUSH = 0x00000040,
};
enum {
LOCK_STATE_WRITE = 1<<31,
LOCK_STATE_MAPPED = 1<<30,
LOCK_STATE_READ_MASK = 0x3FFFFFFF
PRIV_FLAGS_SW_LOCK = 0x00000080,
PRIV_FLAGS_NONCONTIGUOUS_MEM = 0x00000100,
PRIV_FLAGS_HWC_LOCK = 0x00000200, // Set by HWC when storing the handle
};
// file-descriptors
int fd;
int genlockHandle; // genlock handle to be dup'd by the binder
// ints
int magic;
int flags;
@ -297,23 +300,22 @@ struct private_handle_t {
// FIXME: the attributes below should be out-of-line
int base;
int lockState;
int writeOwner;
int gpuaddr; // The gpu address mapped into the mmu. If using ashmem, set to 0 They don't care
int pid;
int format;
int width;
int height;
int genlockPrivFd; // local fd of the genlock device.
#ifdef __cplusplus
static const int sNumInts = 13;
static const int sNumFds = 1;
static const int sNumInts = 12;
static const int sNumFds = 2;
static const int sMagic = 'gmsm';
private_handle_t(int fd, int size, int flags, int bufferType, int format, int width, int height) :
fd(fd), magic(sMagic), flags(flags), size(size), offset(0), bufferType(bufferType),
base(0), lockState(0), writeOwner(0), gpuaddr(0), pid(getpid()), format(format), width(width),
height(height)
fd(fd), genlockHandle(-1), magic(sMagic), flags(flags), size(size), offset(0),
bufferType(bufferType), base(0), gpuaddr(0), pid(getpid()), format(format),
width(width), height(height), genlockPrivFd(-1)
{
version = sizeof(native_handle);
numInts = sNumInts;

View File

@ -139,10 +139,9 @@ int IonAlloc::alloc_buffer(alloc_data& data)
close(ionSyncFd);
ionSyncFd = FD_INIT;
// Not doing memset for ION, uncomment if needed
// memset(base, 0, ionAllocData.len);
memset(base, 0, ionAllocData.len);
// Clean cache after memset
// clean_buffer(base, data.size, data.offset, fd_data.fd);
clean_buffer(base, data.size, data.offset, fd_data.fd);
data.base = base;
data.fd = fd_data.fd;
ioctl(mIonFd, ION_IOC_FREE, &handle_data);

186
libgralloc/mapper.cpp Normal file → Executable file
View File

@ -34,6 +34,7 @@
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <genlock.h>
#include <linux/android_pmem.h>
@ -132,8 +133,31 @@ int gralloc_register_buffer(gralloc_module_t const* module,
private_handle_t* hnd = (private_handle_t*)handle;
if (hnd->pid != getpid()) {
hnd->base = 0;
hnd->lockState = 0;
hnd->writeOwner = 0;
void *vaddr;
int err = gralloc_map(module, handle, &vaddr);
if (err) {
LOGE("%s: gralloc_map failed", __FUNCTION__);
return err;
}
// Reset the genlock private fd flag in the handle
hnd->genlockPrivFd = -1;
// Check if there is a valid lock attached to the handle.
if (-1 == hnd->genlockHandle) {
LOGE("%s: the lock is invalid.", __FUNCTION__);
gralloc_unmap(module, handle);
hnd->base = 0;
return -EINVAL;
}
// Attach the genlock handle
if (GENLOCK_FAILURE == genlock_attach_lock((native_handle_t *)handle)) {
LOGE("%s: genlock_attach_lock failed", __FUNCTION__);
gralloc_unmap(module, handle);
hnd->base = 0;
return -EINVAL;
}
}
return 0;
}
@ -152,18 +176,19 @@ int gralloc_unregister_buffer(gralloc_module_t const* module,
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) {
if (hnd->base != 0) {
gralloc_unmap(module, handle);
}
hnd->base = 0;
hnd->lockState = 0;
hnd->writeOwner = 0;
// Release the genlock
if (-1 != hnd->genlockHandle) {
return genlock_release_lock((native_handle_t *)handle);
} else {
LOGE("%s: there was no genlock attached to this buffer", __FUNCTION__);
return -EINVAL;
}
}
return 0;
}
@ -176,11 +201,7 @@ int terminateBuffer(gralloc_module_t const* module,
* 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) {
if (hnd->base != 0) {
// this buffer was mapped, unmap it now
if (hnd->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM |
private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP |
@ -211,70 +232,43 @@ int gralloc_lock(gralloc_module_t const* module,
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 requesting sw write for non-framebuffer handles, flag for
// flushing at unlock
if ((usage & GRALLOC_USAGE_SW_WRITE_MASK) &&
!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
}
if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
if (!(current_value & private_handle_t::LOCK_STATE_MAPPED)) {
if (hnd->base == 0) {
// 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));
}
}
err = gralloc_map(module, handle, vaddr);
pthread_mutex_unlock(lock);
}
*vaddr = (void*)hnd->base;
}
// Lock the buffer for read/write operation as specified. Write lock
// has a higher priority over read lock.
int lockType = 0;
if (usage & GRALLOC_USAGE_SW_WRITE_MASK) {
lockType = GENLOCK_WRITE_LOCK;
} else if (usage & GRALLOC_USAGE_SW_READ_MASK) {
lockType = GENLOCK_READ_LOCK;
}
int timeout = GENLOCK_MAX_TIMEOUT;
if (GENLOCK_FAILURE == genlock_lock_buffer((native_handle_t *)handle,
(genlock_lock_type)lockType,
timeout)) {
LOGE("%s: genlock_lock_buffer (lockType=0x%x) failed", __FUNCTION__,
lockType);
return -EINVAL;
} else {
// Mark this buffer as locked for SW read/write operation.
hnd->flags |= private_handle_t::PRIV_FLAGS_SW_LOCK;
}
if ((usage & GRALLOC_USAGE_SW_WRITE_MASK) &&
!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
// Mark the buffer to be flushed after cpu read/write
hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
}
}
return err;
}
@ -285,7 +279,6 @@ int gralloc_unlock(gralloc_module_t const* module,
return -EINVAL;
private_handle_t* hnd = (private_handle_t*)handle;
int32_t current_value, new_value;
if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) {
int err;
@ -297,28 +290,14 @@ int gralloc_unlock(gralloc_module_t const* module,
hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
}
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);
if ((hnd->flags & private_handle_t::PRIV_FLAGS_SW_LOCK)) {
// Unlock the buffer.
if (GENLOCK_FAILURE == genlock_unlock_buffer((native_handle_t *)handle)) {
LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__);
return -EINVAL;
}
new_value--;
} while (android_atomic_cmpxchg(current_value, new_value,
(volatile int32_t*)&hnd->lockState));
} else
hnd->flags &= ~private_handle_t::PRIV_FLAGS_SW_LOCK;
}
return 0;
}
@ -330,7 +309,6 @@ int gralloc_perform(struct gralloc_module_t const* module,
int res = -EINVAL;
va_list args;
va_start(args, operation);
#if 0
switch (operation) {
case GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER:
{
@ -338,6 +316,9 @@ int gralloc_perform(struct gralloc_module_t const* module,
size_t size = va_arg(args, size_t);
size_t offset = va_arg(args, size_t);
void* base = va_arg(args, void*);
int width = va_arg(args, int);
int height = va_arg(args, int);
int format = va_arg(args, int);
native_handle_t** handle = va_arg(args, native_handle_t**);
int memoryFlags = va_arg(args, int);
@ -367,31 +348,18 @@ int gralloc_perform(struct gralloc_module_t const* module,
hnd->size = size;
hnd->offset = offset;
hnd->base = intptr_t(base) + offset;
hnd->lockState = private_handle_t::LOCK_STATE_MAPPED;
hnd->gpuaddr = 0;
hnd->width = width;
hnd->height = height;
hnd->format = format;
*handle = (native_handle_t *)hnd;
res = 0;
break;
}
case GRALLOC_MODULE_PERFORM_UPDATE_BUFFER_HANDLE:
{
native_handle_t* handle = va_arg(args, native_handle_t*);
int w = va_arg(args, int);
int h = va_arg(args, int);
int f = va_arg(args, int);
private_handle_t* hnd = (private_handle_t*)handle;
hnd->width = w;
hnd->height = h;
if (hnd->format != f) {
hnd->format = f;
}
break;
}
default:
break;
}
#endif
va_end(args);
return res;
}

8
libhwcomposer/Android.mk Normal file → Executable file
View File

@ -6,18 +6,26 @@ include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libcutils libEGL libhardware libutils liboverlay
LOCAL_SHARED_LIBRARIES += libgenlock
LOCAL_SRC_FILES := \
hwcomposer.cpp
LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).hwcomposer\"
LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc
LOCAL_C_INCLUDES += hardware/qcom/display/liboverlay
LOCAL_C_INCLUDES += hardware/qcom/display/libcopybit
LOCAL_C_INCLUDES += hardware/qcom/display/libgenlock
LOCAL_C_INCLUDES += hardware/qcom/display/libqcomui
ifeq ($(TARGET_HAVE_HDMI_OUT),true)
LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY
endif
ifeq ($(TARGET_USES_OVERLAY),true)
LOCAL_CFLAGS += -DUSE_OVERLAY
endif
ifeq ($(TARGET_HAVE_BYPASS),true)
LOCAL_CFLAGS += -DCOMPOSITION_BYPASS
endif

277
libhwcomposer/hwcomposer.cpp Normal file → Executable file
View File

@ -37,6 +37,8 @@
#include <EGL/eglext.h>
#include <ui/android_native_buffer.h>
#include <gralloc_priv.h>
#include <genlock.h>
#include <qcom_ui.h>
/*****************************************************************************/
#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1))
@ -58,12 +60,6 @@ enum HWCCompositionType {
HWC_USE_COPYBIT // This layer is to be handled by copybit
};
enum HWCPrivateFlags {
HWC_USE_ORIGINAL_RESOLUTION = HWC_FLAGS_PRIVATE_0, // This layer is to be drawn using overlays
HWC_DO_NOT_USE_OVERLAY = HWC_FLAGS_PRIVATE_1, // Do not use overlays to draw this layer
HWC_COMP_BYPASS = HWC_FLAGS_PRIVATE_3, // Layer "might" use or have used bypass
};
enum HWCLayerType{
HWC_SINGLE_VIDEO = 0x1,
HWC_ORIG_RESOLUTION = 0x2,
@ -82,6 +78,11 @@ enum {
MAX_BYPASS_LAYERS = 2,
ANIM_FRAME_COUNT = 30,
};
enum BypassBufferLockState {
BYPASS_BUFFER_UNLOCKED,
BYPASS_BUFFER_LOCKED,
};
#endif
enum eHWCOverlayStatus {
@ -94,8 +95,11 @@ struct hwc_context_t {
hwc_composer_device_t device;
/* our private state goes below here */
overlay::Overlay* mOverlayLibObject;
native_handle_t *previousOverlayHandle;
#ifdef COMPOSITION_BYPASS
overlay::OverlayUI* mOvUI[MAX_BYPASS_LAYERS];
native_handle_t* previousBypassHandle[MAX_BYPASS_LAYERS];
BypassBufferLockState bypassBufferLockState[MAX_BYPASS_LAYERS];
int animCount;
BypassState bypassState;
#endif
@ -227,14 +231,39 @@ static int hwc_closeOverlayChannels(hwc_context_t* ctx) {
#ifdef COMPOSITION_BYPASS
// To-do: Merge this with other blocks & move them to a separate file.
void unlockPreviousBypassBuffers(hwc_context_t* ctx) {
// Unlock the previous bypass buffers. We can blindly unlock the buffers here,
// because buffers will be in this list only if the lock was successfully acquired.
for(int i = 0; i < MAX_BYPASS_LAYERS; i++) {
if (ctx->previousBypassHandle[i]) {
private_handle_t *hnd = (private_handle_t*) ctx->previousBypassHandle[i];
// Validate the handle to make sure it hasn't been deallocated.
if (private_handle_t::validate(ctx->previousBypassHandle[i])) {
continue;
}
// Check if the handle was locked previously
if (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags) {
if (GENLOCK_FAILURE == genlock_unlock_buffer(ctx->previousBypassHandle[i])) {
LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__);
} else {
ctx->previousBypassHandle[i] = NULL;
// Reset the lock flag
hnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK;
}
}
}
}
}
void closeBypass(hwc_context_t* ctx) {
for (int index = 0 ; index < MAX_BYPASS_LAYERS; index++) {
ctx->mOvUI[index]->closeChannel();
unlockPreviousBypassBuffers(ctx);
for (int index = 0 ; index < MAX_BYPASS_LAYERS; index++) {
ctx->mOvUI[index]->closeChannel();
}
#ifdef DEBUG
LOGE("%s", __FUNCTION__);
#endif
}
}
#endif
/*
@ -307,6 +336,25 @@ static int prepareOverlay(hwc_context_t *ctx, hwc_layer_t *layer, const bool wai
return 0;
}
void unlockPreviousOverlayBuffer(hwc_context_t* ctx)
{
if (ctx->previousOverlayHandle) {
// Validate the handle before attempting to use it.
if (!private_handle_t::validate(ctx->previousOverlayHandle)) {
private_handle_t *hnd = (private_handle_t*)ctx->previousOverlayHandle;
// Unlock any previously locked buffers
if (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags) {
if (GENLOCK_NO_ERROR == genlock_unlock_buffer(ctx->previousOverlayHandle)) {
ctx->previousOverlayHandle = NULL;
hnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK;
} else {
LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__);
}
}
}
}
}
bool canSkipComposition(hwc_context_t* ctx, int yuvBufferCount, int currentLayerCount,
int numLayersNotUpdating)
{
@ -459,9 +507,21 @@ static int drawLayerUsingBypass(hwc_context_t *ctx, hwc_layer_t *layer,
overlay::OverlayUI *ovUI = ctx->mOvUI[index];
int ret = 0;
private_handle_t *hnd = (private_handle_t *)layer->handle;
ctx->bypassBufferLockState[index] = BYPASS_BUFFER_UNLOCKED;
if (GENLOCK_FAILURE == genlock_lock_buffer(hnd, GENLOCK_READ_LOCK,
GENLOCK_MAX_TIMEOUT)) {
LOGE("%s: genlock_lock_buffer(READ) failed", __FUNCTION__);
return -1;
}
ctx->bypassBufferLockState[index] = BYPASS_BUFFER_LOCKED;
ret = ovUI->queueBuffer(hnd);
if (ret) {
LOGE("drawLayerUsingBypass queueBuffer failed");
// Unlock the locked buffer
if (GENLOCK_FAILURE == genlock_unlock_buffer(hnd)) {
LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__);
}
ctx->bypassBufferLockState[index] = BYPASS_BUFFER_UNLOCKED;
return -1;
}
}
@ -498,9 +558,26 @@ static bool isDisjoint(const hwc_layer_list_t* list) {
return true;
}
static bool usesContiguousMemory(const hwc_layer_list_t* list) {
for(int i = 0; i < list->numHwLayers; i++) {
const private_handle_t *hnd =
reinterpret_cast<const private_handle_t *>(list->hwLayers[i].handle);
if(hnd != NULL && (hnd->flags &
private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM
)) {
// Bypass cannot work for non contiguous buffers
return false;
}
}
return true;
}
/*
* Checks if doing comp. bypass is possible. If video is not on and there
* are 2 layers then its doable.
* Checks if doing comp. bypass is possible.
* It is possible if
* 1. If video is not on
* 2. There are 2 layers
* 3. The memory type is contiguous
*/
inline static bool isBypassDoable(hwc_composer_device_t *dev, const int yuvCount,
const hwc_layer_list_t* list) {
@ -511,6 +588,9 @@ inline static bool isBypassDoable(hwc_composer_device_t *dev, const int yuvCount
if(hwcModule->isBypassEnabled == false) {
return false;
}
// Check if memory type is contiguous
if(!usesContiguousMemory(list))
return false;
//Disable bypass during animation
if(UNLIKELY(ctx->animCount)) {
--(ctx->animCount);
@ -570,6 +650,25 @@ void unsetBypassLayerFlags(hwc_layer_list_t* list) {
}
}
void unsetBypassBufferLockState(hwc_context_t* ctx) {
for (int i=0; i< MAX_BYPASS_LAYERS; i++) {
ctx->bypassBufferLockState[i] = BYPASS_BUFFER_UNLOCKED;
}
}
void storeLockedBypassHandle(hwc_layer_list_t* list, hwc_context_t* ctx) {
for (int index = 0 ; index < list->numHwLayers; index++) {
// Store the current bypass handle.
if (list->hwLayers[index].flags == HWC_COMP_BYPASS) {
private_handle_t *hnd = (private_handle_t*)list->hwLayers[index].handle;
if (ctx->bypassBufferLockState[index] == BYPASS_BUFFER_LOCKED) {
ctx->previousBypassHandle[index] = (native_handle_t*)list->hwLayers[index].handle;
hnd->flags |= private_handle_t::PRIV_FLAGS_HWC_LOCK;
} else
ctx->previousBypassHandle[index] = NULL;
}
}
}
#endif //COMPOSITION_BYPASS
@ -708,15 +807,20 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
hwc_context_t* ctx = (hwc_context_t*)(dev);
if(!ctx || !list) {
LOGE("hwc_prepare invalid context or list");
return -1;
if(!ctx) {
LOGE("hwc_prepare invalid context");
return -1;
}
private_hwc_module_t* hwcModule = reinterpret_cast<private_hwc_module_t*>(
dev->common.module);
if(!hwcModule) {
LOGE("hwc_prepare null module ");
if (!list || !hwcModule) {
LOGE("hwc_prepare invalid list or module");
#ifdef COMPOSITION_BYPASS
unlockPreviousBypassBuffers(ctx);
unsetBypassBufferLockState(ctx);
#endif
unlockPreviousOverlayBuffer(ctx);
return -1;
}
@ -739,6 +843,8 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
s3dVideoFormat = getS3DVideoFormat(list);
if (s3dVideoFormat)
isS3DCompositionNeeded = isS3DCompositionRequired();
} else {
unlockPreviousOverlayBuffer(ctx);
}
if (list->flags & HWC_GEOMETRY_CHANGED) {
@ -757,29 +863,55 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
// need to still mark the layer for S3D composition
if (isS3DCompositionNeeded)
markUILayerForS3DComposition(list->hwLayers[i], s3dVideoFormat);
if (hwcModule->compositionType
& (COMPOSITION_TYPE_C2D | COMPOSITION_TYPE_MDP)) {
// Ensure that HWC_OVERLAY layers below skip layers do not
// overwrite GPU composed skip layers.
ssize_t layer_countdown = ((ssize_t)i) - 1;
while (layer_countdown >= 0)
{
// Mark every non-mdp overlay layer below the
// skip-layer for GPU composition.
switch(list->hwLayers[layer_countdown].compositionType) {
case HWC_FRAMEBUFFER:
case HWC_USE_OVERLAY:
break;
case HWC_USE_COPYBIT:
default:
list->hwLayers[layer_countdown].compositionType = HWC_FRAMEBUFFER;
break;
}
layer_countdown--;
}
}
continue;
}
if (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) && (yuvBufferCount == 1)) {
bool waitForVsync = skipComposition ? true:false;
bool waitForVsync = true;
if (!isValidDestination(hwcModule->fbDevice, list->hwLayers[i].displayFrame)) {
list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
skipComposition = false;
#ifdef USE_OVERLAY
} else if(prepareOverlay(ctx, &(list->hwLayers[i]), waitForVsync) == 0) {
list->hwLayers[i].compositionType = HWC_USE_OVERLAY;
list->hwLayers[i].hints |= HWC_HINT_CLEAR_FB;
// We've opened the channel. Set the state to open.
ctx->hwcOverlayStatus = HWC_OVERLAY_OPEN;
#endif
}
else if (hwcModule->compositionType & (COMPOSITION_TYPE_C2D)) {
else if (hwcModule->compositionType & (COMPOSITION_TYPE_C2D|
COMPOSITION_TYPE_MDP)) {
//Fail safe path: If drawing with overlay fails,
//Use C2D if available.
list->hwLayers[i].compositionType = HWC_USE_COPYBIT;
skipComposition = false;
}
else {
//If C2D is not enabled fall back to GPU.
list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
}
if (HWC_USE_OVERLAY != list->hwLayers[i].compositionType) {
unlockPreviousOverlayBuffer(ctx);
skipComposition = false;
}
} else if (isS3DCompositionNeeded) {
@ -819,7 +951,9 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) {
ctx->bypassState = BYPASS_ON;
}
} else {
unlockPreviousBypassBuffers(ctx);
unsetBypassLayerFlags(list);
unsetBypassBufferLockState(ctx);
if(ctx->bypassState == BYPASS_ON) {
ctx->bypassState = BYPASS_OFF_PENDING;
}
@ -887,6 +1021,14 @@ static int drawLayerUsingCopybit(hwc_composer_device_t *dev, hwc_layer_t *layer,
return -1;
}
// Lock this buffer for read.
genlock_lock_type lockType = GENLOCK_READ_LOCK;
int err = genlock_lock_buffer(hnd, lockType, GENLOCK_MAX_TIMEOUT);
if (GENLOCK_FAILURE == err) {
LOGE("%s: genlock_lock_buffer(READ) failed", __FUNCTION__);
return -1;
}
// Set the copybit source:
copybit_image_t src;
src.w = ALIGN(hnd->width, 32);
@ -894,6 +1036,11 @@ static int drawLayerUsingCopybit(hwc_composer_device_t *dev, hwc_layer_t *layer,
src.format = hnd->format;
src.base = (void *)hnd->base;
src.handle = (native_handle_t *)layer->handle;
src.horiz_padding = src.w - hnd->width;
// Initialize vertical padding to zero for now,
// this needs to change to accomodate vertical stride
// if needed in the future
src.vert_padding = 0;
// Copybit source rect
hwc_rect_t sourceCrop = layer->sourceCrop;
@ -912,11 +1059,13 @@ static int drawLayerUsingCopybit(hwc_composer_device_t *dev, hwc_layer_t *layer,
android_native_buffer_t *renderBuffer = (android_native_buffer_t *)eglGetRenderBufferANDROID(dpy, surface);
if (!renderBuffer) {
LOGE("eglGetRenderBufferANDROID returned NULL buffer");
genlock_unlock_buffer(hnd);
return -1;
}
private_handle_t *fbHandle = (private_handle_t *)renderBuffer->handle;
if(!fbHandle) {
LOGE("Framebuffer handle is NULL");
genlock_unlock_buffer(hnd);
return -1;
}
dst.w = ALIGN(fbHandle->width,32);
@ -930,16 +1079,24 @@ static int drawLayerUsingCopybit(hwc_composer_device_t *dev, hwc_layer_t *layer,
region_iterator copybitRegion(region);
copybit_device_t *copybit = hwcModule->copybitEngine;
copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH, renderBuffer->width);
copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT, renderBuffer->height);
copybit->set_parameter(copybit, COPYBIT_TRANSFORM, layer->transform);
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA,
(layer->blending == HWC_BLENDING_NONE) ? 0xFF : layer->alpha);
copybit->set_parameter(copybit, COPYBIT_PREMULTIPLIED_ALPHA,
(layer->blending == HWC_BLENDING_PREMULT)? COPYBIT_ENABLE : COPYBIT_DISABLE);
int err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect, &copybitRegion);
err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect, &copybitRegion);
if(err < 0)
LOGE("copybit stretch failed");
// Unlock this buffer since copybit is done with it.
err = genlock_unlock_buffer(hnd);
if (GENLOCK_FAILURE == err) {
LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__);
}
return err;
}
@ -955,13 +1112,33 @@ static int drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer)
overlay::Overlay *ovLibObject = ctx->mOverlayLibObject;
int ret = 0;
ret = ovLibObject->queueBuffer(hnd);
if (!ret) {
LOGE("drawLayerUsingOverlay queueBuffer failed");
// Lock this buffer for read.
if (GENLOCK_NO_ERROR != genlock_lock_buffer(hnd, GENLOCK_READ_LOCK,
GENLOCK_MAX_TIMEOUT)) {
LOGE("%s: genlock_lock_buffer(READ) failed", __FUNCTION__);
return -1;
}
ret = ovLibObject->queueBuffer(hnd);
// Unlock the previously locked buffer, since the overlay has completed reading the buffer
unlockPreviousOverlayBuffer(ctx);
if (!ret) {
LOGE("drawLayerUsingOverlay queueBuffer failed");
// Unlock the buffer handle
genlock_unlock_buffer(hnd);
ctx->previousOverlayHandle = NULL;
} else {
// Store the current buffer handle as the one that is to be unlocked after
// the next overlay play call.
ctx->previousOverlayHandle = hnd;
hnd->flags |= private_handle_t::PRIV_FLAGS_HWC_LOCK;
}
return ret;
}
return 0;
return -1;
}
static int hwc_set(hwc_composer_device_t *dev,
@ -970,15 +1147,23 @@ static int hwc_set(hwc_composer_device_t *dev,
hwc_layer_list_t* list)
{
hwc_context_t* ctx = (hwc_context_t*)(dev);
if(!ctx || !list) {
LOGE("hwc_set invalid context or list");
return -1;
if(!ctx) {
LOGE("hwc_set invalid context");
return -1;
}
private_hwc_module_t* hwcModule = reinterpret_cast<private_hwc_module_t*>(
dev->common.module);
if(!hwcModule) {
LOGE("hwc_set null module ");
framebuffer_device_t *fbDev = hwcModule->fbDevice;
if (!list || !hwcModule) {
LOGE("hwc_set invalid list or module");
#ifdef COMPOSITION_BYPASS
unlockPreviousBypassBuffers(ctx);
unsetBypassBufferLockState(ctx);
#endif
unlockPreviousOverlayBuffer(ctx);
return -1;
}
@ -1000,15 +1185,34 @@ static int hwc_set(hwc_composer_device_t *dev,
}
}
#ifdef COMPOSITION_BYPASS
unlockPreviousBypassBuffers(ctx);
storeLockedBypassHandle(list, ctx);
// We have stored the handles, unset the current lock states in the context.
unsetBypassBufferLockState(ctx);
//Setup for waiting until 1 FB post is done before closing bypass mode.
if (ctx->bypassState == BYPASS_OFF_PENDING) {
fbDev->resetBufferPostStatus(fbDev);
}
#endif
// Do not call eglSwapBuffers if we the skip composition flag is set on the list.
if (!(list->flags & HWC_SKIP_COMPOSITION)) {
EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur);
if (!sucess) {
ret = HWC_EGL_ERROR;
LOGE("eglSwapBuffers() failed in %s", __FUNCTION__);
}
}
#ifdef COMPOSITION_BYPASS
if(ctx->bypassState == BYPASS_OFF_PENDING) {
//Close channels only after fb content is displayed.
//We have already reset status before eglSwapBuffers.
if (!(list->flags & HWC_SKIP_COMPOSITION)) {
fbDev->waitForBufferPost(fbDev);
}
closeBypass(ctx);
ctx->bypassState = BYPASS_OFF;
}
@ -1047,13 +1251,17 @@ static int hwc_device_close(struct hw_device_t *dev)
hwcModule->fbDevice = NULL;
}
unlockPreviousOverlayBuffer(ctx);
if (ctx) {
delete ctx->mOverlayLibObject;
ctx->mOverlayLibObject = NULL;
#ifdef COMPOSITION_BYPASS
for(int i = 0; i < MAX_BYPASS_LAYERS; i++) {
delete ctx->mOvUI[i];
}
for(int i = 0; i < MAX_BYPASS_LAYERS; i++) {
delete ctx->mOvUI[i];
}
unlockPreviousBypassBuffers(ctx);
unsetBypassBufferLockState(ctx);
#endif
free(ctx);
}
@ -1130,7 +1338,9 @@ static int hwc_device_open(const struct hw_module_t* module, const char* name,
#ifdef COMPOSITION_BYPASS
for(int i = 0; i < MAX_BYPASS_LAYERS; i++) {
dev->mOvUI[i] = new overlay::OverlayUI();
dev->previousBypassHandle[i] = NULL;
}
unsetBypassBufferLockState(dev);
dev->animCount = 0;
dev->bypassState = BYPASS_OFF;
#endif
@ -1139,6 +1349,7 @@ static int hwc_device_open(const struct hw_module_t* module, const char* name,
dev->mHDMIEnabled = false;
dev->pendingHDMI = false;
#endif
dev->previousOverlayHandle = NULL;
dev->hwcOverlayStatus = HWC_OVERLAY_CLOSED;
/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;

View File

@ -256,8 +256,21 @@ bool overlay::enableBarrier (unsigned int orientation) {
int overlay::getColorFormat(int format)
{
return (format == HAL_PIXEL_FORMAT_YV12) ?
format : COLOR_FORMAT(format);
if (format == HAL_PIXEL_FORMAT_YV12)
return format;
else if (format & INTERLACE_MASK)
return format ^ HAL_PIXEL_FORMAT_INTERLACE;
else
return COLOR_FORMAT(format);
}
bool overlay::isInterlacedContent(int format)
{
if ((format != HAL_PIXEL_FORMAT_YV12) &&
(format & INTERLACE_MASK))
return true;
return false;
}
unsigned int overlay::getOverlayConfig (unsigned int format3D, bool poll,
@ -466,8 +479,8 @@ bool Overlay::updateOverlaySource(const overlay_buffer_info& info, int orientati
int orientHdmi = 0;
int orientPrimary = sHDMIAsPrimary ? 0 : orientation;
int orient[2] = {orientPrimary, orientHdmi};
// enable waitForVsync on HDMI
bool waitForHDMI = true;
// disable waitForVsync on HDMI, since we call the wait ioctl
bool waitForHDMI = false;
bool waitForPrimary = sHDMIAsPrimary ? true : waitForVsync;
bool waitCond[2] = {waitForPrimary, waitForHDMI};
@ -582,7 +595,7 @@ bool Overlay::setSource(const overlay_buffer_info& info, int orientation,
if (FRAMEBUFFER_1 == i) {
// Disable rotation for HDMI
noRot = true;
waitForVsync = true;
waitForVsync = false;
}
if(!startChannel(info, i, noRot, false, mS3DFormat,
i, waitForVsync, num_buffers)) {
@ -715,6 +728,10 @@ bool Overlay::queueBuffer(uint32_t offset, int channel) {
return objOvDataChannel[channel].queueBuffer(offset);
}
bool Overlay::waitForHdmiVsync(int channel) {
return objOvDataChannel[channel].waitForHdmiVsync();
}
bool Overlay::queueBuffer(buffer_handle_t buffer) {
private_handle_t const* hnd = reinterpret_cast
<private_handle_t const*>(buffer);
@ -737,12 +754,17 @@ bool Overlay::queueBuffer(buffer_handle_t buffer) {
case OV_3D_VIDEO_3D_PANEL:
case OV_3D_VIDEO_2D_TV:
case OV_3D_VIDEO_3D_TV:
for (int i=0; i<NUM_CHANNELS; i++) {
for (int i=NUM_CHANNELS-1; i>=0; i--) {
if(!queueBuffer(fd, offset, i)) {
LOGE("%s:failed for channel %d", __FUNCTION__, i);
return false;
}
}
//Wait for HDMI done..
if(!waitForHdmiVsync(VG1_PIPE)) {
LOGE("%s: waitforHdmiVsync failed", __FUNCTION__);
return false;
}
break;
default:
LOGE("%s:Unknown state %d", __FUNCTION__, mState);
@ -961,8 +983,8 @@ bool OverlayControlChannel::setOverlayInformation(const overlay_buffer_info& inf
mOVInfo.z_order = zorder;
mOVInfo.alpha = 0xff;
mOVInfo.transp_mask = 0xffffffff;
mOVInfo.flags = flags;
}
mOVInfo.flags = flags;
if (!ignoreFB)
mOVInfo.flags |= MDP_OV_PLAY_NOWAIT;
else
@ -1042,7 +1064,9 @@ bool OverlayControlChannel::updateOverlaySource(const overlay_buffer_info& info,
ovBufInfo.height = info.height;
ovBufInfo.format = hw_format;
if (!setOverlayInformation(ovBufInfo, 0, orientation, 0, waitForVsync, UPDATE_REQUEST))
int flags = isInterlacedContent(info.format) ? MDP_DEINTERLACE : 0;
if (!setOverlayInformation(ovBufInfo, flags, orientation, 0, waitForVsync,
UPDATE_REQUEST))
return false;
return startOVRotatorSessions(ovBufInfo, orientation, UPDATE_REQUEST);
@ -1063,7 +1087,7 @@ bool OverlayControlChannel::startControlChannel(int w, int h,
int colorFormat = format;
// The interlace mask is part of the HAL_PIXEL_FORMAT_YV12 value. Add
// an explicit check for the format
if ((format != HAL_PIXEL_FORMAT_YV12) && (format & INTERLACE_MASK)) {
if (isInterlacedContent(format)) {
flags |= MDP_DEINTERLACE;
// Get the actual format
@ -1608,6 +1632,19 @@ bool OverlayDataChannel::queue(uint32_t offset) {
reportError("overlay play failed.");
return false;
}
return true;
}
bool OverlayDataChannel::waitForHdmiVsync() {
if (!isChannelUP()) {
reportError("waitForHdmiVsync: channel not up");
return false;
}
if (ioctl(mFD, MSMFB_OVERLAY_PLAY_WAIT, &mOvData)) {
reportError("waitForHdmiVsync: MSMFB_OVERLAY_PLAY_WAIT failed");
return false;
}
return true;
}

View File

@ -144,6 +144,7 @@ bool enableBarrier(unsigned int orientation);
unsigned int getOverlayConfig (unsigned int format3D, bool poll = true,
bool isHDMI = false);
int getColorFormat(int format);
bool isInterlacedContent(int format);
int get_mdp_format(int format);
int get_size(int format, int w, int h);
int get_rot_output_format(int format);
@ -250,6 +251,7 @@ public:
bool closeDataChannel();
bool setFd(int fd);
bool queueBuffer(uint32_t offset);
bool waitForHdmiVsync();
bool setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
bool getCropS3D(overlay_rect *inRect, int channel, int format, overlay_rect *rect);
bool isChannelUP() const { return (mFD > 0); }
@ -297,6 +299,7 @@ public:
bool setSource(const overlay_buffer_info& info, int orientation, bool hdmiConnected,
bool ignoreFB = false, int numBuffers = 2);
bool setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
bool waitForHdmiVsync(int channel);
int getChannelStatus() const { return (mChannelUP ? OVERLAY_CHANNEL_UP: OVERLAY_CHANNEL_DOWN); }
void setHDMIStatus (bool isHDMIConnected) { mHDMIConnected = isHDMIConnected; mState = -1; }
int getHDMIStatus() const {return (mHDMIConnected ? HDMI_ON : HDMI_OFF); }

17
libqcomui/Android.mk Normal file
View File

@ -0,0 +1,17 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
qcom_ui.cpp
LOCAL_SHARED_LIBRARIES := \
libutils \
libcutils \
libmemalloc \
libui
LOCAL_C_INCLUDES := $(TOP)/hardware/qcom/display/libgralloc \
LOCAL_CFLAGS := -DLOG_TAG=\"libQcomUI\"
LOCAL_MODULE := libQcomUI
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)

293
libqcomui/qcom_ui.cpp Normal file
View File

@ -0,0 +1,293 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cutils/log.h>
#include <qcom_ui.h>
#include <gralloc_priv.h>
#include <alloc_controller.h>
#include <memalloc.h>
#include <errno.h>
using gralloc::IMemAlloc;
using gralloc::IonController;
using gralloc::alloc_data;
using android::sp;
namespace {
static android::sp<gralloc::IAllocController> sAlloc = 0;
int reallocate_memory(native_handle_t *buffer_handle, int mReqSize, int usage)
{
int ret = 0;
if (sAlloc == 0) {
sAlloc = gralloc::IAllocController::getInstance(true);
}
if (sAlloc == 0) {
LOGE("sAlloc is still NULL");
return -EINVAL;
}
// Dealloc the old memory
private_handle_t *hnd = (private_handle_t *)buffer_handle;
sp<IMemAlloc> memalloc = sAlloc->getAllocator(hnd->flags);
ret = memalloc->free_buffer((void*)hnd->base, hnd->size, hnd->offset, hnd->fd);
if (ret) {
LOGE("%s: free_buffer failed", __FUNCTION__);
return -1;
}
// Realloc new memory
alloc_data data;
data.base = 0;
data.fd = -1;
data.offset = 0;
data.size = mReqSize;
data.align = getpagesize();
data.uncached = true;
int allocFlags = usage;
switch (hnd->format) {
case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
case (HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED^HAL_PIXEL_FORMAT_INTERLACE): {
data.align = 8192;
} break;
default: break;
}
ret = sAlloc->allocate(data, allocFlags, 0);
if (ret == 0) {
hnd->fd = data.fd;
hnd->base = (int)data.base;
hnd->offset = data.offset;
hnd->size = data.size;
} else {
LOGE("%s: allocate failed", __FUNCTION__);
return -EINVAL;
}
return ret;
}
}; // ANONYNMOUS NAMESPACE
/*
* Gets the number of arguments required for this operation.
*
* @param: operation whose argument count is required.
*
* @return -EINVAL if the operation is invalid.
*/
int getNumberOfArgsForOperation(int operation) {
int num_args = -EINVAL;
switch(operation) {
case NATIVE_WINDOW_SET_BUFFERS_SIZE:
num_args = 1;
break;
case NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY:
num_args = 3;
break;
default: LOGE("%s: invalid operation(0x%x)", __FUNCTION__, operation);
break;
};
return num_args;
}
/*
* Checks if the format is supported by the GPU.
*
* @param: format to check
*
* @return true if the format is supported by the GPU.
*/
bool isGPUSupportedFormat(int format) {
bool isSupportedFormat = true;
switch(format) {
case (HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED^HAL_PIXEL_FORMAT_INTERLACE):
case (HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED|HAL_3D_OUT_SIDE_BY_SIDE
|HAL_3D_IN_SIDE_BY_SIDE_R_L):
case (HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED|HAL_3D_OUT_SIDE_BY_SIDE
|HAL_3D_IN_SIDE_BY_SIDE_L_R):
isSupportedFormat = false;
break;
default: break;
}
return isSupportedFormat;
}
/*
* Function to check if the allocated buffer is of the correct size.
* Reallocate the buffer with the correct size, if the size doesn't
* match
*
* @param: handle of the allocated buffer
* @param: requested size for the buffer
* @param: usage flags
*
* return 0 on success
*/
int checkBuffer(native_handle_t *buffer_handle, int size, int usage)
{
// If the client hasn't set a size, return
if (0 == size) {
return 0;
}
// Validate the handle
if (private_handle_t::validate(buffer_handle)) {
LOGE("%s: handle is invalid", __FUNCTION__);
return -EINVAL;
}
// Obtain the private_handle from the native handle
private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
if (hnd->size < size) {
return reallocate_memory(hnd, size, usage);
}
return 0;
}
/*
* Checks if memory needs to be reallocated for this buffer.
*
* @param: Geometry of the current buffer.
* @param: Required Geometry.
* @param: Geometry of the updated buffer.
*
* @return True if a memory reallocation is required.
*/
bool needNewBuffer(const qBufGeometry currentGeometry,
const qBufGeometry requiredGeometry,
const qBufGeometry updatedGeometry)
{
// If the current buffer info matches the updated info,
// we do not require any memory allocation.
if (updatedGeometry.width && updatedGeometry.height &&
updatedGeometry.format) {
return false;
}
if (currentGeometry.width != requiredGeometry.width ||
currentGeometry.height != requiredGeometry.height ||
currentGeometry.format != requiredGeometry.format) {
// Current and required geometry do not match. Allocation
// required.
return true;
}
return false;
}
/*
* Update the geometry of this buffer without reallocation.
*
* @param: buffer whose geometry needs to be updated.
* @param: Updated width
* @param: Updated height
* @param: Updated format
*/
int updateBufferGeometry(sp<GraphicBuffer> buffer, const qBufGeometry updatedGeometry)
{
if (buffer == 0) {
LOGE("%s: graphic buffer is NULL", __FUNCTION__);
return -EINVAL;
}
if (!updatedGeometry.width || !updatedGeometry.height ||
!updatedGeometry.format) {
// No update required. Return.
return 0;
}
if (buffer->width == updatedGeometry.width &&
buffer->height == updatedGeometry.height &&
buffer->format == updatedGeometry.format) {
// The buffer has already been updated. Return.
return 0;
}
// Validate the handle
if (private_handle_t::validate(buffer->handle)) {
LOGE("%s: handle is invalid", __FUNCTION__);
return -EINVAL;
}
buffer->width = updatedGeometry.width;
buffer->height = updatedGeometry.height;
buffer->format = updatedGeometry.format;
private_handle_t *hnd = (private_handle_t*)(buffer->handle);
if (hnd) {
hnd->width = updatedGeometry.width;
hnd->height = updatedGeometry.height;
hnd->format = updatedGeometry.format;
} else {
LOGE("%s: hnd is NULL", __FUNCTION__);
return -EINVAL;
}
return 0;
}
/*
* Updates the flags for the layer
*
* @param: Attribute
* @param: Identifies if the attribute was enabled or disabled.
*
* @return: -EINVAL if the attribute is invalid
*/
int updateLayerQcomFlags(eLayerAttrib attribute, bool enable, int& currentFlags)
{
int ret = 0;
switch (attribute) {
case LAYER_UPDATE_STATUS: {
if (enable)
currentFlags |= LAYER_UPDATING;
else
currentFlags &= ~LAYER_UPDATING;
} break;
default: LOGE("%s: invalid attribute(0x%x)", __FUNCTION__, attribute);
break;
}
return ret;
}
/*
* Gets the per frame HWC flags for this layer.
*
* @param: current hwcl flags
* @param: current layerFlags
*
* @return: the per frame flags.
*/
int getPerFrameFlags(int hwclFlags, int layerFlags) {
int flags = hwclFlags;
if (layerFlags & LAYER_UPDATING)
flags &= ~HWC_LAYER_NOT_UPDATING;
else
flags |= HWC_LAYER_NOT_UPDATING;
return flags;
}

158
libqcomui/qcom_ui.h Normal file
View File

@ -0,0 +1,158 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef INCLUDE_LIBQCOM_UI
#define INCLUDE_LIBQCOM_UI
#include <cutils/native_handle.h>
#include <ui/GraphicBuffer.h>
using android::sp;
using android::GraphicBuffer;
/*
* Qcom specific Native Window perform operations
*/
enum {
NATIVE_WINDOW_SET_BUFFERS_SIZE = 0x10000000,
NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY = 0x20000000,
};
/*
* Layer Attributes
*/
enum eLayerAttrib {
LAYER_UPDATE_STATUS,
};
/*
* Layer Flags
*/
enum {
LAYER_UPDATING = 1<<0,
};
/*
* Flags set by the layer and sent to HWC
*/
enum {
HWC_LAYER_NOT_UPDATING = 0x00000002,
HWC_USE_ORIGINAL_RESOLUTION = 0x10000000,
HWC_DO_NOT_USE_OVERLAY = 0x20000000,
HWC_COMP_BYPASS = 0x40000000,
};
/*
* Structure to hold the buffer geometry
*/
struct qBufGeometry {
int width;
int height;
int format;
void set(int w, int h, int f) {
width = w;
height = h;
format = f;
}
};
/*
* Function to check if the allocated buffer is of the correct size.
* Reallocate the buffer with the correct size, if the size doesn't
* match
*
* @param: handle of the allocated buffer
* @param: requested size for the buffer
* @param: usage flags
*
* return 0 on success
*/
int checkBuffer(native_handle_t *buffer_handle, int size, int usage);
/*
* Checks if the format is supported by the GPU.
*
* @param: format to check
*
* @return true if the format is supported by the GPU.
*/
bool isGPUSupportedFormat(int format);
/*
* Gets the number of arguments required for this operation.
*
* @param: operation whose argument count is required.
*
* @return -EINVAL if the operation is invalid.
*/
int getNumberOfArgsForOperation(int operation);
/*
* Checks if memory needs to be reallocated for this buffer.
*
* @param: Geometry of the current buffer.
* @param: Required Geometry.
* @param: Geometry of the updated buffer.
*
* @return True if a memory reallocation is required.
*/
bool needNewBuffer(const qBufGeometry currentGeometry,
const qBufGeometry requiredGeometry,
const qBufGeometry updatedGeometry);
/*
* Update the geometry of this buffer without reallocation.
*
* @param: buffer whose geometry needs to be updated.
* @param: Updated buffer geometry
*/
int updateBufferGeometry(sp<GraphicBuffer> buffer, const qBufGeometry bufGeometry);
/*
* Updates the flags for the layer
*
* @param: Attribute
* @param: Identifies if the attribute was enabled or disabled.
* @param: current Layer flags.
*
* @return: Flags for the layer
*/
int updateLayerQcomFlags(eLayerAttrib attribute, bool enable, int& currentFlags);
/*
* Gets the per frame HWC flags for this layer.
*
* @param: current hwcl flags
* @param: current layerFlags
*
* @return: the per frame flags.
*/
int getPerFrameFlags(int hwclFlags, int layerFlags);
#endif // INCLUDE_LIBQCOM_UI

View File

@ -0,0 +1,26 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_SHARED_LIBRARIES := libutils libcutils libGLESv2 libhwui
LOCAL_C_INCLUDES += \
frameworks/base/include/utils \
frameworks/base/libs/hwui \
external/skia/include/core \
external/skia/include/effects \
external/skia/include/images \
external/skia/src/ports \
external/skia/include/utils \
hardware/libhardware/include/hardware \
frameworks/base/opengl/include/GLES2
LOCAL_SRC_FILES := \
tilerenderer.cpp
LOCAL_MODULE := libtilerenderer
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
endif

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (c) 2011 Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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 <GLES2/gl2.h>
#include <EGL/egl.h>
#include <gl2ext.h>
#include <OpenGLRenderer.h>
#include "tilerenderer.h"
namespace android {
ANDROID_SINGLETON_STATIC_INSTANCE(uirenderer::TileRenderer) ;
namespace uirenderer {
TileRenderer::TileRenderer() {
mIsTiled = false;
}
TileRenderer::~TileRenderer() {
}
void TileRenderer::startTileRendering(OpenGLRenderer* renderer,
int left, int top,
int right, int bottom) {
int width = 0;
int height = 0;
GLenum status = GL_NO_ERROR;
if (renderer != NULL) {
renderer->getViewport(width, height);
}
if (!left && !right && !top && !bottom) {
left = 0;
top = 0;
right = width;
bottom = height;
}
if (!left && !right && !top && !bottom) {
//can't do tile rendering
LOGE("can't tile render; drity region, width, height not available");
return;
}
int l = left, t = (height - bottom), w = (right - left), h = (bottom - top), preserve = 0;
if (l < 0 || t < 0) {
l = (l < 0) ? 0 : l;
t = (t < 0) ? 0 : t;
preserve = 1;
}
if (w > width || h > height) {
w = (w > width) ? width : w;
h = (h > height) ? height : h;
preserve = 1;
}
//clear off all errors before tiling, if any
while ((status = glGetError()) != GL_NO_ERROR) {
LOGE("glStartTilingQCOM: 0x%x", status);
}
if (preserve)
glStartTilingQCOM(l, t, w, h, GL_COLOR_BUFFER_BIT0_QCOM);
else
glStartTilingQCOM(l, t, w, h, GL_NONE);
status = glGetError();
if (status == GL_NO_ERROR)
mIsTiled = true;
else
LOGE("glStartTilingQCOM: 0x%x", status);
}
void TileRenderer::endTileRendering(OpenGLRenderer*) {
if (!mIsTiled) {
return;
}
glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
mIsTiled = false;
GLenum status = GL_NO_ERROR;
while ((status = glGetError()) != GL_NO_ERROR) {
LOGE("glEndTilingQCOM: 0x%x", status);
}
}
}; // namespace uirenderer
}; // namespace android

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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_TILE_RENDERER_H
#define ANDROID_TILE_RENDERER_H
#include <utils/Singleton.h>
namespace android {
namespace uirenderer {
class OpenGLRenderer;
class TileRenderer: public Singleton<TileRenderer> {
public:
TileRenderer();
~TileRenderer();
void startTileRendering(OpenGLRenderer* renderer, int left, int top, int right, int bottom);
void endTileRendering(OpenGLRenderer*);
private:
bool mIsTiled;
};
}; // namespace uirenderer
}; // namespace android
#endif