From aa4994d543a6ac4b5b154aaf6fb81b2339d74e57 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Mon, 21 Nov 2011 20:42:54 -0800 Subject: [PATCH 01/33] Add a generic buffer locking API. Add libgenlock which is a cross-process buffer locking API. libgenlock provides the ability to create, attach, release locks. It also provides a mechanism to lock and unlock buffers for read/write purposes. Change-Id: I5172a82539b83bcb1226e3fd4f7b80a5c7f31016 --- Android.mk | 2 +- libgenlock/Android.mk | 15 ++ libgenlock/genlock.cpp | 301 ++++++++++++++++++++++++++++++++++++++ libgenlock/genlock.h | 118 +++++++++++++++ libgralloc/gralloc_priv.h | 12 +- 5 files changed, 442 insertions(+), 6 deletions(-) create mode 100644 libgenlock/Android.mk create mode 100644 libgenlock/genlock.cpp create mode 100644 libgenlock/genlock.h diff --git a/Android.mk b/Android.mk index 1f6937f..a3295d0 100644 --- a/Android.mk +++ b/Android.mk @@ -1,4 +1,4 @@ #Enables the listed display HAL modules -display-hals := libhwcomposer liboverlay libgralloc libcopybit +display-hals := libhwcomposer liboverlay libgralloc libgenlock libcopybit include $(call all-named-subdir-makefiles,$(display-hals)) diff --git a/libgenlock/Android.mk b/libgenlock/Android.mk new file mode 100644 index 0000000..d8a3dfe --- /dev/null +++ b/libgenlock/Android.mk @@ -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) + diff --git a/libgenlock/genlock.cpp b/libgenlock/genlock.cpp new file mode 100644 index 0000000..36c2a22 --- /dev/null +++ b/libgenlock/genlock.cpp @@ -0,0 +1,301 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "genlock.h" + +#define GENLOCK_DEVICE "/dev/genlock" + +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(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) +{ + 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; + } + + genlock_status_t ret = GENLOCK_NO_ERROR; + // Create a new lock + private_handle_t *hnd = reinterpret_cast(buffer_handle); + 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; + 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) +{ + if (private_handle_t::validate(buffer_handle)) { + LOGE("%s: handle is invalid", __FUNCTION__); + return GENLOCK_FAILURE; + } + + genlock_status_t ret = GENLOCK_NO_ERROR; + private_handle_t *hnd = reinterpret_cast(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); + 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) +{ + 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; + } + + genlock_status_t ret = GENLOCK_NO_ERROR; + // Attach the local handle to an existing lock + private_handle_t *hnd = reinterpret_cast(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; + 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) +{ + // 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. + return perform_lock_unlock_operation(buffer_handle, kLockType, 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) +{ + // Do the unlock operation by setting the unlock flag. Timeout is always + // 0 in this case. + return perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0); +} + +/* + * 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) { + if (private_handle_t::validate(buffer_handle)) { + LOGE("%s: handle is invalid", __FUNCTION__); + return GENLOCK_FAILURE; + } + + private_handle_t *hnd = reinterpret_cast(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; + } + return GENLOCK_NO_ERROR; +} diff --git a/libgenlock/genlock.h b/libgenlock/genlock.h new file mode 100644 index 0000000..b394410 --- /dev/null +++ b/libgenlock/genlock.h @@ -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 + +#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 diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 0130b6e..1d990ba 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -288,6 +288,7 @@ struct private_handle_t { // file-descriptors int fd; + int genlockHandle; // genlock handle to be dup'd by the binder // ints int magic; int flags; @@ -304,16 +305,17 @@ struct private_handle_t { 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 = 14; + 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), lockState(0), writeOwner(0), gpuaddr(0), + pid(getpid()), format(format), width(width), height(height), genlockPrivFd(-1) { version = sizeof(native_handle); numInts = sNumInts; From 1b5f80522ba8aa1d93873ec790777289d33ddced Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Sun, 20 Nov 2011 00:12:03 -0800 Subject: [PATCH 02/33] libgralloc: Create, attach and release genlock locks Add support in the gralloc to: - Create a lock during buffer allocation. - Release a lock when the buffer is freed or unregistered. - Attach a lock when the buffer is registered. Change-Id: I788e411f43d5fcf88d7dcf39c530559a12d6361c --- libgralloc/Android.mk | 2 ++ libgralloc/gpu.cpp | 16 ++++++++++++++++ libgralloc/mapper.cpp | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+) mode change 100644 => 100755 libgralloc/Android.mk mode change 100644 => 100755 libgralloc/gpu.cpp mode change 100644 => 100755 libgralloc/mapper.cpp diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk old mode 100644 new mode 100755 index 545c1d3..a95babb --- a/libgralloc/Android.mk +++ b/libgralloc/Android.mk @@ -21,8 +21,10 @@ 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 += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_C_INCLUDES += hardware/qcom/display/libgenlock LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_SRC_FILES := framebuffer.cpp \ gpu.cpp \ diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp old mode 100644 new mode 100755 index e0f3ebb..da9f4c1 --- a/libgralloc/gpu.cpp +++ b/libgralloc/gpu.cpp @@ -21,6 +21,8 @@ #include #include +#include + #include "gr.h" #include "gpu.h" #include "memalloc.h" @@ -289,6 +291,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(pHandle)); + return err; + } *pStride = alignedw; return 0; } @@ -308,6 +317,13 @@ int gpu_context_t::free_impl(private_handle_t const* hnd) { return err; terminateBuffer(&m->base, const_cast(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; } diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp old mode 100644 new mode 100755 index d6024b0..e324552 --- a/libgralloc/mapper.cpp +++ b/libgralloc/mapper.cpp @@ -34,6 +34,7 @@ #include #include +#include #include @@ -134,6 +135,17 @@ int gralloc_register_buffer(gralloc_module_t const* module, hnd->base = 0; hnd->lockState = 0; hnd->writeOwner = 0; + // 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__); + return -EINVAL; + } + + // Attach the genlock handle + return genlock_attach_lock((native_handle_t *)handle); } return 0; } @@ -164,6 +176,14 @@ int gralloc_unregister_buffer(gralloc_module_t const* module, 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; } From 09367ef6e8fb13ffe28945c5c73be8e03d756bdd Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Sun, 20 Nov 2011 00:21:11 -0800 Subject: [PATCH 03/33] libgralloc: Map buffers during registration Map the gralloc buffer during the register_buffer phase. This allows the clients to obtain the virtual address without the need to call an additional mmap. Change-Id: I9377584ee564ad5113fd353b727793f16d7b9b94 --- libgralloc/mapper.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp index e324552..da1b2fa 100755 --- a/libgralloc/mapper.cpp +++ b/libgralloc/mapper.cpp @@ -133,6 +133,13 @@ int gralloc_register_buffer(gralloc_module_t const* module, private_handle_t* hnd = (private_handle_t*)handle; if (hnd->pid != getpid()) { hnd->base = 0; + void *vaddr; + int err = gralloc_map(module, handle, &vaddr); + if (err) { + LOGE("%s: gralloc_map failed", __FUNCTION__); + return err; + } + hnd->lockState = 0; hnd->writeOwner = 0; // Reset the genlock private fd flag in the handle @@ -141,11 +148,18 @@ int gralloc_register_buffer(gralloc_module_t const* module, // 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 - return genlock_attach_lock((native_handle_t *)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; } From 1e746398262084c4d9edf5d34670cfe05189cc20 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Sun, 20 Nov 2011 00:40:05 -0800 Subject: [PATCH 04/33] libgralloc: Invoke genlock during gralloc_lock/gralloc_unlock gralloc_lock and gralloc_unlock invokes genlock to perform the buffer locking operation. Remove unused gralloc handle variables. Change-Id: I5283613c5f67f708123916653af1b2d1ec155577 --- libgralloc/gpu.cpp | 1 - libgralloc/gralloc_priv.h | 15 ++--- libgralloc/mapper.cpp | 131 +++++++++++--------------------------- 3 files changed, 42 insertions(+), 105 deletions(-) diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp index da9f4c1..014c54b 100755 --- a/libgralloc/gpu.cpp +++ b/libgralloc/gpu.cpp @@ -172,7 +172,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; } diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 1d990ba..ced31f6 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -278,12 +278,7 @@ 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, }; // file-descriptors @@ -298,8 +293,6 @@ 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; @@ -308,14 +301,14 @@ struct private_handle_t { int genlockPrivFd; // local fd of the genlock device. #ifdef __cplusplus - static const int sNumInts = 14; + 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), genlockHandle(-1), 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), genlockPrivFd(-1) + bufferType(bufferType), base(0), gpuaddr(0), pid(getpid()), format(format), + width(width), height(height), genlockPrivFd(-1) { version = sizeof(native_handle); numInts = sNumInts; diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp index da1b2fa..2c01b15 100755 --- a/libgralloc/mapper.cpp +++ b/libgralloc/mapper.cpp @@ -140,8 +140,6 @@ int gralloc_register_buffer(gralloc_module_t const* module, return err; } - hnd->lockState = 0; - hnd->writeOwner = 0; // Reset the genlock private fd flag in the handle hnd->genlockPrivFd = -1; @@ -178,19 +176,12 @@ 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); @@ -210,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 | @@ -245,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; } @@ -319,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; @@ -331,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; } From 229856bedf9aa8c95b560fa2bd41236af5b8b8f7 Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Mon, 21 Nov 2011 19:51:25 -0800 Subject: [PATCH 05/33] HWC: Fix for non-overlay targets Do not call prepareOverlay, instead use copybit to compose video frames Change-Id: I5e85b0b65009de37ab792e59d259d8f1879fb0c4 --- libhwcomposer/Android.mk | 3 +++ libhwcomposer/hwcomposer.cpp | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk index 71ebf63..9338b1d 100644 --- a/libhwcomposer/Android.mk +++ b/libhwcomposer/Android.mk @@ -20,6 +20,9 @@ LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr 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 diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index c43d5c1..e94549e 100644 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -764,13 +764,16 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { 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. From dce3b38f5855919f6246cbf0d21ef39b9fd72855 Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Wed, 23 Nov 2011 17:31:59 -0800 Subject: [PATCH 06/33] display: Ashmem: use MAP_POPULATE when mapping If the flag is not used, it causes errors with mapping the page tables in the kgsl driver Change-Id: Iaa29eb764aff8a9af4b14fff9fdab60b50759e45 --- libgralloc/ashmemalloc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libgralloc/ashmemalloc.cpp b/libgralloc/ashmemalloc.cpp index 49926f8..7102090 100644 --- a/libgralloc/ashmemalloc.cpp +++ b/libgralloc/ashmemalloc.cpp @@ -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", From 95ab7ecd2c48ee10875363d0deaefead162974be Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Wed, 23 Nov 2011 18:11:14 -0800 Subject: [PATCH 07/33] copybit: Do not do in-place conversion for YV12 Change-Id: I7e53f44baa6e924c6923d4e1d1af9454f51a7357 --- libcopybit/copybit.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp index 9807aef..42378ea 100644 --- a/libcopybit/copybit.cpp +++ b/libcopybit/copybit.cpp @@ -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(src))->format = + HAL_PIXEL_FORMAT_YCrCb_420_SP; } else{ LOGE("Error copybit conversion from yv12 failed"); From be1b5f3d66d063e7506ab32ad39556d3127031a5 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Mon, 21 Nov 2011 21:01:30 -0800 Subject: [PATCH 08/33] libhwcomposer: Use genlock to lock/unlock buffers for composition. For copybit composition, aquire a read lock on the buffer, before the blit operation and release the lock after the blit operation. For overlay, aquire a read lock on buffer N that is sent to the overlay. After the play call for buffer N returns, unlock the lock held by buffer (N-1). Change-Id: I3ff178d8ed8e3a289c199237dbec501afdb7e717 --- libhwcomposer/Android.mk | 4 ++ libhwcomposer/hwcomposer.cpp | 75 ++++++++++++++++++++++++++++++++---- 2 files changed, 72 insertions(+), 7 deletions(-) mode change 100644 => 100755 libhwcomposer/Android.mk mode change 100644 => 100755 libhwcomposer/hwcomposer.cpp diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk old mode 100644 new mode 100755 index 9338b1d..099ee2f --- a/libhwcomposer/Android.mk +++ b/libhwcomposer/Android.mk @@ -6,16 +6,20 @@ 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 += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include + LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr ifeq ($(TARGET_HAVE_HDMI_OUT),true) LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp old mode 100644 new mode 100755 index e94549e..8a5676f --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -37,6 +37,7 @@ #include #include #include +#include /*****************************************************************************/ #define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) @@ -94,6 +95,7 @@ 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]; int animCount; @@ -739,6 +741,12 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { s3dVideoFormat = getS3DVideoFormat(list); if (s3dVideoFormat) isS3DCompositionNeeded = isS3DCompositionRequired(); + } else { + if (ctx->previousOverlayHandle) { + // Unlock any previously locked buffers + if (GENLOCK_NO_ERROR == genlock_unlock_buffer(ctx->previousOverlayHandle)) + ctx->previousOverlayHandle = NULL; + } } if (list->flags & HWC_GEOMETRY_CHANGED) { @@ -763,7 +771,6 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { bool waitForVsync = skipComposition ? true:false; 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; @@ -778,11 +785,17 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { //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) { + if (ctx->previousOverlayHandle) { + // Unlock any previously locked buffers before the fallback. + if (GENLOCK_NO_ERROR == genlock_unlock_buffer(ctx->previousOverlayHandle)) + ctx->previousOverlayHandle = NULL; + } skipComposition = false; } } else if (isS3DCompositionNeeded) { @@ -890,6 +903,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); @@ -915,11 +936,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); @@ -938,11 +961,17 @@ static int drawLayerUsingCopybit(hwc_composer_device_t *dev, hwc_layer_t *layer, (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, ©bitRegion); + err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect, ©bitRegion); 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; } @@ -958,13 +987,37 @@ 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 + if (ctx->previousOverlayHandle) { + if (GENLOCK_FAILURE == genlock_unlock_buffer(ctx->previousOverlayHandle)) { + LOGE("%s: genlock_unlock_buffer for the previous handle failed", + __FUNCTION__); + } + } + + 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; + } + + return ret; } - return 0; + return -1; } static int hwc_set(hwc_composer_device_t *dev, @@ -1050,6 +1103,13 @@ static int hwc_device_close(struct hw_device_t *dev) hwcModule->fbDevice = NULL; } + if (ctx->previousOverlayHandle) { + if (GENLOCK_NO_ERROR != genlock_unlock_buffer(ctx->previousOverlayHandle)) { + LOGE("%s: genlock_unlock_buffer for the previous handle failed", + __FUNCTION__); + } + } + if (ctx) { delete ctx->mOverlayLibObject; ctx->mOverlayLibObject = NULL; @@ -1142,6 +1202,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; From d415cbf061f8de78013d225ab20e7140ba2be93b Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Wed, 23 Nov 2011 19:38:56 -0800 Subject: [PATCH 09/33] libgenlock: Add compile time flag. Add a compile time flag USE_GENLOCK to enable/disable genlock. Change-Id: I3b442a52b446c2a5e0417ba1058460bdee02fc90 --- libgenlock/genlock.cpp | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/libgenlock/genlock.cpp b/libgenlock/genlock.cpp index 36c2a22..2aa709a 100644 --- a/libgenlock/genlock.cpp +++ b/libgenlock/genlock.cpp @@ -113,11 +113,14 @@ namespace { */ 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(buffer_handle); +#ifdef USE_GENLOCK // Open the genlock device int fd = open(GENLOCK_DEVICE, O_RDWR); if (fd < 0) { @@ -126,9 +129,7 @@ genlock_status_t genlock_create_lock(native_handle_t *buffer_handle) return GENLOCK_FAILURE; } - genlock_status_t ret = GENLOCK_NO_ERROR; // Create a new lock - private_handle_t *hnd = reinterpret_cast(buffer_handle); genlock_lock lock; if (ioctl(fd, GENLOCK_IOC_NEW, NULL)) { LOGE("%s: GENLOCK_IOC_NEW failed (error=%s)", __FUNCTION__, @@ -150,6 +151,9 @@ genlock_status_t genlock_create_lock(native_handle_t *buffer_handle) // Store the lock params in the handle. hnd->genlockPrivFd = fd; hnd->genlockHandle = lock.fd; +#else + hnd->genlockHandle = 0; +#endif return ret; } @@ -162,12 +166,13 @@ genlock_status_t genlock_create_lock(native_handle_t *buffer_handle) */ 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; } - genlock_status_t ret = GENLOCK_NO_ERROR; private_handle_t *hnd = reinterpret_cast(buffer_handle); if (hnd->genlockPrivFd < 0) { LOGE("%s: the lock is invalid", __FUNCTION__); @@ -182,6 +187,7 @@ genlock_status_t genlock_release_lock(native_handle_t *buffer_handle) // Close the fd and reset the parameters. close_genlock_fd_and_handle(hnd->genlockPrivFd, hnd->genlockHandle); +#endif return ret; } @@ -194,6 +200,8 @@ genlock_status_t genlock_release_lock(native_handle_t *buffer_handle) */ 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; @@ -207,7 +215,6 @@ genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle) return GENLOCK_FAILURE; } - genlock_status_t ret = GENLOCK_NO_ERROR; // Attach the local handle to an existing lock private_handle_t *hnd = reinterpret_cast(buffer_handle); genlock_lock lock; @@ -221,6 +228,7 @@ genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle) // Store the relavant information in the handle hnd->genlockPrivFd = fd; +#endif return ret; } @@ -240,6 +248,8 @@ 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) { @@ -251,7 +261,9 @@ genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle, LOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__); } // Call the private function to perform the lock operation specified. - return perform_lock_unlock_operation(buffer_handle, kLockType, timeout); + ret = perform_lock_unlock_operation(buffer_handle, kLockType, timeout); +#endif + return ret; } @@ -263,9 +275,13 @@ genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle, */ 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. - return perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0); + ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0); +#endif + return ret; } /* @@ -276,6 +292,7 @@ genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle) * 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; @@ -297,5 +314,6 @@ genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout) { LOGE("%s: GENLOCK_IOC_WAIT failed (err=%s)", __FUNCTION__, strerror(errno)); return GENLOCK_FAILURE; } +#endif return GENLOCK_NO_ERROR; } From 0e8663d5f222fb4e16c090acb62d38e9f2959297 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Mon, 28 Nov 2011 15:25:32 -0800 Subject: [PATCH 10/33] libgenlock: Enable the USE_GENLOCK flag. Change-Id: I2349de455eb82f2b10d2ccac1c318d7cef2901ae --- libgenlock/genlock.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libgenlock/genlock.cpp b/libgenlock/genlock.cpp index 2aa709a..37bcc0e 100644 --- a/libgenlock/genlock.cpp +++ b/libgenlock/genlock.cpp @@ -38,6 +38,10 @@ #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) From e2de425bc44ef4983c4b43721f2e64bba41162a5 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Mon, 28 Nov 2011 15:29:08 -0800 Subject: [PATCH 11/33] Display: Set WAIT on primary and NO_WAIT on HDMI When queuing buffers using the overlay: - Set the NO_WAIT flag for the HDMI channel. - Set the WAIT flag for the primary channel. - Queue the buffer on the HDMI first. - Queue the buffer on the primary. - Wait for the HDMI Vsync. Change-Id: Id24e9551230b7a7134bd21a7b3a9e8658f7de222 --- libhwcomposer/hwcomposer.cpp | 2 +- liboverlay/overlayLib.cpp | 30 ++++++++++++++++++++++++++---- liboverlay/overlayLib.h | 2 ++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index 8a5676f..6fa6b41 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -768,7 +768,7 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { 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; #ifdef USE_OVERLAY diff --git a/liboverlay/overlayLib.cpp b/liboverlay/overlayLib.cpp index c468c4e..5245fc2 100755 --- a/liboverlay/overlayLib.cpp +++ b/liboverlay/overlayLib.cpp @@ -466,8 +466,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 +582,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 +715,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 (buffer); @@ -737,12 +741,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=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); @@ -1608,6 +1617,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; } diff --git a/liboverlay/overlayLib.h b/liboverlay/overlayLib.h index aebb075..0a502ea 100755 --- a/liboverlay/overlayLib.h +++ b/liboverlay/overlayLib.h @@ -250,6 +250,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 +298,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); } From f54edbd924f1eabdc520eb60fbbb712fec7c7182 Mon Sep 17 00:00:00 2001 From: Rajulu Ponnada Date: Tue, 29 Nov 2011 11:32:48 -0800 Subject: [PATCH 12/33] hardware/qcom/display: support for QCOM tiled rendering Tiled rendering implementation. Change-Id: I1d1361b175fdb6f64b47df85b8f68bebd7d1eea5 --- Android.mk | 2 +- libtilerenderer/Android.mk | 26 ++++++++ libtilerenderer/tilerenderer.cpp | 103 +++++++++++++++++++++++++++++++ libtilerenderer/tilerenderer.h | 42 +++++++++++++ 4 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 libtilerenderer/Android.mk create mode 100644 libtilerenderer/tilerenderer.cpp create mode 100644 libtilerenderer/tilerenderer.h diff --git a/Android.mk b/Android.mk index a3295d0..373fbfc 100644 --- a/Android.mk +++ b/Android.mk @@ -1,4 +1,4 @@ #Enables the listed display HAL modules -display-hals := libhwcomposer liboverlay libgralloc libgenlock libcopybit +display-hals := libhwcomposer liboverlay libgralloc libgenlock libcopybit libtilerenderer include $(call all-named-subdir-makefiles,$(display-hals)) diff --git a/libtilerenderer/Android.mk b/libtilerenderer/Android.mk new file mode 100644 index 0000000..e0bf342 --- /dev/null +++ b/libtilerenderer/Android.mk @@ -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 diff --git a/libtilerenderer/tilerenderer.cpp b/libtilerenderer/tilerenderer.cpp new file mode 100644 index 0000000..ae12ecf --- /dev/null +++ b/libtilerenderer/tilerenderer.cpp @@ -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 +#include +#include +#include +#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 diff --git a/libtilerenderer/tilerenderer.h b/libtilerenderer/tilerenderer.h new file mode 100644 index 0000000..bec225d --- /dev/null +++ b/libtilerenderer/tilerenderer.h @@ -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 + +namespace android { +namespace uirenderer { + +class OpenGLRenderer; + +class TileRenderer: public Singleton { +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 From b0e7470e4ffc988c6e5be3903124cc3cfef5088c Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Tue, 29 Nov 2011 19:12:53 -0800 Subject: [PATCH 13/33] libhwcomposer: Lock/unlock bypass buffers using genlock Use genlock to lock the bypass buffers before they are queued to the overlay. After all the bypass buffers are queued, use genlock to unlock the previously locked bypass buffers. Change-Id: Ifdd7921f0c9f5d5744c899a0257a4b954274334b --- libhwcomposer/hwcomposer.cpp | 76 +++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index 6fa6b41..e1f72a5 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -83,6 +83,11 @@ enum { MAX_BYPASS_LAYERS = 2, ANIM_FRAME_COUNT = 30, }; + +enum BypassBufferLockState { + BYPASS_BUFFER_UNLOCKED, + BYPASS_BUFFER_LOCKED, +}; #endif enum eHWCOverlayStatus { @@ -98,6 +103,8 @@ struct hwc_context_t { 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 @@ -229,14 +236,30 @@ 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]; + if (GENLOCK_FAILURE == genlock_unlock_buffer(ctx->previousBypassHandle[i])) { + LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); + } else { + ctx->previousBypassHandle[i] = NULL; + } + } + } +} + 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 /* @@ -461,9 +484,20 @@ 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; + 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; } } @@ -572,6 +606,24 @@ 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; + else + ctx->previousBypassHandle[index] = NULL; + } + } +} #endif //COMPOSITION_BYPASS @@ -835,7 +887,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; } @@ -1056,6 +1110,12 @@ 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); +#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); @@ -1114,9 +1174,11 @@ static int hwc_device_close(struct hw_device_t *dev) 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); } @@ -1193,7 +1255,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 From e5a9508bad1d6917e45be94ed2d32287cfd48714 Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Thu, 1 Dec 2011 23:26:28 -0800 Subject: [PATCH 14/33] display: gralloc: zero out the alloc'd ion buffer Change-Id: Ib92863cf03f284eb24729bbad449795e7bd47d44 --- libgralloc/ionalloc.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libgralloc/ionalloc.cpp b/libgralloc/ionalloc.cpp index d92dedc..e91ee2f 100644 --- a/libgralloc/ionalloc.cpp +++ b/libgralloc/ionalloc.cpp @@ -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); From 8994068ce6313470004ba94221ce2c0271f51413 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Mon, 28 Nov 2011 10:58:01 -0800 Subject: [PATCH 15/33] libgralloc: Add HAL_PIXEL_FORMAT_NV12_ENCODEABLE format. Add HAL_PIXEL_FORMAT_NV12_ENCODEABLE which is the encoder specific format. Remove unused OEM formats from the gralloc. Change-Id: I787203cd96b597c881f0acc10b60ea2ab2ffe1ab --- libgralloc/gpu.cpp | 14 ++++++++------ libgralloc/gralloc_priv.h | 9 +-------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp index 014c54b..8909b95 100755 --- a/libgralloc/gpu.cpp +++ b/libgralloc/gpu.cpp @@ -28,11 +28,6 @@ #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; @@ -248,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: @@ -257,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; diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index ced31f6..5461ede 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -155,14 +155,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, From f79ec0f39840694596b663eb403a6e5f673f2554 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Tue, 29 Nov 2011 16:00:36 -0800 Subject: [PATCH 16/33] libcopybit: Add copybit iterator. Add the copybit iterator which takes a single rectangle as an input. Change-Id: I6fd496450c29ed06ffbfad62b5c880e837450791 --- libcopybit/copybit_priv.h | 57 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 libcopybit/copybit_priv.h diff --git a/libcopybit/copybit_priv.h b/libcopybit/copybit_priv.h new file mode 100644 index 0000000..7fdd508 --- /dev/null +++ b/libcopybit/copybit_priv.h @@ -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 +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(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; +}; + From ba64a65af2567302054b3c2457e5176bb1bcb053 Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Wed, 23 Nov 2011 12:25:38 -0800 Subject: [PATCH 17/33] libgralloc: Add gralloc perform to create handle from a buffer Change-Id: I11fb9add49f32cc5d518baf47cb61507474f6809 --- libgralloc/gralloc_priv.h | 7 +++++++ libgralloc/mapper.cpp | 23 ++++++----------------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 5461ede..6118001 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -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, diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp index 2c01b15..2cecbd5 100755 --- a/libgralloc/mapper.cpp +++ b/libgralloc/mapper.cpp @@ -309,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: { @@ -317,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); @@ -346,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; } From 599d9a41bc204a2b436c22732e34b17d214eb5d6 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Fri, 2 Dec 2011 16:09:31 -0800 Subject: [PATCH 18/33] libhwcomposer: Unlock buffers if the input params are invalid. If the input parameters in the prepare and set functions are invalid, unlock any previously locked buffers. Change-Id: Ifd3b02c3ae6d2095970d5e15b98196d7fa7dee4e CRs-fixed: 322054 --- libhwcomposer/hwcomposer.cpp | 68 +++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index e1f72a5..9ad98c7 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -332,6 +332,18 @@ 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) { + // Unlock any previously locked buffers + if (GENLOCK_NO_ERROR == genlock_unlock_buffer(ctx->previousOverlayHandle)) { + ctx->previousOverlayHandle = NULL; + } else { + LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); + } + } +} + bool canSkipComposition(hwc_context_t* ctx, int yuvBufferCount, int currentLayerCount, int numLayersNotUpdating) { @@ -762,15 +774,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( 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; } @@ -794,11 +811,7 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { if (s3dVideoFormat) isS3DCompositionNeeded = isS3DCompositionRequired(); } else { - if (ctx->previousOverlayHandle) { - // Unlock any previously locked buffers - if (GENLOCK_NO_ERROR == genlock_unlock_buffer(ctx->previousOverlayHandle)) - ctx->previousOverlayHandle = NULL; - } + unlockPreviousOverlayBuffer(ctx); } if (list->flags & HWC_GEOMETRY_CHANGED) { @@ -843,11 +856,7 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; } if (HWC_USE_OVERLAY != list->hwLayers[i].compositionType) { - if (ctx->previousOverlayHandle) { - // Unlock any previously locked buffers before the fallback. - if (GENLOCK_NO_ERROR == genlock_unlock_buffer(ctx->previousOverlayHandle)) - ctx->previousOverlayHandle = NULL; - } + unlockPreviousOverlayBuffer(ctx); skipComposition = false; } } else if (isS3DCompositionNeeded) { @@ -1051,12 +1060,7 @@ static int drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer) ret = ovLibObject->queueBuffer(hnd); // Unlock the previously locked buffer, since the overlay has completed reading the buffer - if (ctx->previousOverlayHandle) { - if (GENLOCK_FAILURE == genlock_unlock_buffer(ctx->previousOverlayHandle)) { - LOGE("%s: genlock_unlock_buffer for the previous handle failed", - __FUNCTION__); - } - } + unlockPreviousOverlayBuffer(ctx); if (!ret) { LOGE("drawLayerUsingOverlay queueBuffer failed"); @@ -1080,15 +1084,20 @@ 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( dev->common.module); - if(!hwcModule) { - LOGE("hwc_set null module "); + if (!list || !hwcModule) { + LOGE("hwc_set invalid list or module"); +#ifdef COMPOSITION_BYPASS + unlockPreviousBypassBuffers(ctx); + unsetBypassBufferLockState(ctx); +#endif + unlockPreviousOverlayBuffer(ctx); return -1; } @@ -1163,12 +1172,7 @@ static int hwc_device_close(struct hw_device_t *dev) hwcModule->fbDevice = NULL; } - if (ctx->previousOverlayHandle) { - if (GENLOCK_NO_ERROR != genlock_unlock_buffer(ctx->previousOverlayHandle)) { - LOGE("%s: genlock_unlock_buffer for the previous handle failed", - __FUNCTION__); - } - } + unlockPreviousOverlayBuffer(ctx); if (ctx) { delete ctx->mOverlayLibObject; From f2dbabe786a12e7e9ae15328550b5ba581c5492e Mon Sep 17 00:00:00 2001 From: Sushil Chauhan Date: Mon, 5 Dec 2011 16:52:39 -0800 Subject: [PATCH 19/33] Bypass: Turn off only after FB content is displayed. Synchronize turning off of composition bypass with display, so that close happens only after FB content is displayed. This fixes blinks observed when bypass needs to be turned off, for reasons other than video content. Change-Id: Id98bddd0cb2a89ea8729a188934ae1cd947cf305 --- libgralloc/Android.mk | 4 +-- libgralloc/framebuffer.cpp | 48 +++++++++++++++++++++++++++++++++++- libgralloc/gralloc_priv.h | 5 ++++ libhwcomposer/hwcomposer.cpp | 16 ++++++++++++ 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk index a95babb..09021b8 100755 --- a/libgralloc/Android.mk +++ b/libgralloc/Android.mk @@ -45,8 +45,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) diff --git a/libgralloc/framebuffer.cpp b/libgralloc/framebuffer.cpp index 19ee4d1..885c614 100644 --- a/libgralloc/framebuffer.cpp +++ b/libgralloc/framebuffer.cpp @@ -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( + 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( + 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) { diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 6118001..0e45e4a 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -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 }; /*****************************************************************************/ diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index 9ad98c7..46962af 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -1091,6 +1091,9 @@ static int hwc_set(hwc_composer_device_t *dev, private_hwc_module_t* hwcModule = reinterpret_cast( dev->common.module); + + framebuffer_device_t *fbDev = hwcModule->fbDevice; + if (!list || !hwcModule) { LOGE("hwc_set invalid list or module"); #ifdef COMPOSITION_BYPASS @@ -1124,16 +1127,29 @@ static int hwc_set(hwc_composer_device_t *dev, 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; } From 2197d5d9246d0009b63fa8333b5379f256d5f80a Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Tue, 6 Dec 2011 11:51:27 -0800 Subject: [PATCH 20/33] libcopybit: Add support for YUV destination targets. Add support in the c2d copybit for YUV destination. We support 2 and 3 plane yuv formats. Change-Id: Ia2b4dadf2966a324e011fea499da996eee8c8c3c --- libcopybit/copybit_c2d.cpp | 365 +++++++++++++++++++++++++++---------- 1 file changed, 273 insertions(+), 92 deletions(-) diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp index f703f05..e3d6308 100644 --- a/libcopybit/copybit_c2d.cpp +++ b/libcopybit/copybit_c2d.cpp @@ -85,18 +85,26 @@ C2D_STATUS (*LINK_c2dDestroySurface)( uint32 surface_id ); #define COPYBIT_SUCCESS 0 #define COPYBIT_FAILURE -1 - -#define RGB_SURFACE 0 -#define YUV_SURFACE 1 -#define NUM_SRC_SURFACES 2 +#define NUM_SURFACES 3 #define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) + +enum { + RGB_SURFACE, + YUV_SURFACE_2_PLANES, + YUV_SURFACE_3_PLANES +}; + +enum eC2DFlags { + FLAGS_PREMULTIPLIED_ALPHA = 1<<0, + FLAGS_YUV_DESTINATION = 1<<1 +}; /******************************************************************************/ /** State information for each device instance */ struct copybit_context_t { struct copybit_device_t device; - unsigned int src[NUM_SRC_SURFACES]; - unsigned int dst; /* dst surface */ + unsigned int src[NUM_SURFACES]; /* src surfaces */ + unsigned int dst[NUM_SURFACES]; /* dst surfaces */ unsigned int trg_transform; /* target transform */ C2D_OBJECT blitState; void *libc2d2; @@ -111,6 +119,21 @@ struct blitlist{ C2D_OBJECT blitObjects[12]; }; +struct bufferInfo { + int width; + int height; + int format; +}; + + +struct yuvPlaneInfo { + int yStride; //luma stride + int plane1_stride; + int plane2_stride; + int plane1_offset; + int plane2_offset; +}; + /** * Common hardware methods */ @@ -148,9 +171,25 @@ static int get_format(int format) { case HAL_PIXEL_FORMAT_RGBA_5551: return C2D_COLOR_FORMAT_5551_RGBA; case HAL_PIXEL_FORMAT_RGBA_4444: return C2D_COLOR_FORMAT_4444_RGBA; case HAL_PIXEL_FORMAT_YCbCr_420_SP: return C2D_COLOR_FORMAT_420_NV12; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:return C2D_COLOR_FORMAT_420_NV12; case HAL_PIXEL_FORMAT_YCrCb_420_SP: return C2D_COLOR_FORMAT_420_NV21; case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: return C2D_COLOR_FORMAT_420_NV12 | C2D_FORMAT_MACROTILED; - default: return -EINVAL; + default: LOGE("%s: invalid format (0x%x", __FUNCTION__, format); return -EINVAL; + } + return -EINVAL; +} + +/* Get the C2D formats needed for conversion to YUV */ +static int get_c2d_format_for_yuv_destination(int halFormat) { + switch (halFormat) { + // We do not swap the RB when the target is YUV + case HAL_PIXEL_FORMAT_RGBX_8888: return C2D_COLOR_FORMAT_8888_ARGB | C2D_FORMAT_DISABLE_ALPHA; + case HAL_PIXEL_FORMAT_RGBA_8888: return C2D_COLOR_FORMAT_8888_ARGB; + // The U and V need to be interchanged when the target is YUV + case HAL_PIXEL_FORMAT_YCbCr_420_SP: return C2D_COLOR_FORMAT_420_NV21; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:return C2D_COLOR_FORMAT_420_NV21; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: return C2D_COLOR_FORMAT_420_NV12; + default: return get_format(halFormat); } return -EINVAL; } @@ -254,11 +293,28 @@ static int is_supported_rgb_format(int format) } } +static int get_num_planes(int format) +{ + switch(format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: { + return 2; + } + case HAL_PIXEL_FORMAT_YV12: { + return 3; + } + default: + return COPYBIT_FAILURE; + } +} + static int is_supported_yuv_format(int format) { switch(format) { case HAL_PIXEL_FORMAT_YCbCr_420_SP: case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: { return COPYBIT_SUCCESS; } @@ -267,8 +323,21 @@ static int is_supported_yuv_format(int format) } } -static int calculate_yuv_offset_and_stride(int format, int width, int height, int *offset, int *yStride, int *uvStride) +static int is_valid_destination_format(int format) { + if (format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) { + // C2D does not support NV12Tile as a destination format. + return COPYBIT_FAILURE; + } + return COPYBIT_SUCCESS; +} + +static int calculate_yuv_offset_and_stride(const bufferInfo& info, yuvPlaneInfo& yuvInfo) +{ + int width = info.width; + int height = info.height; + int format = info.format; + int aligned_height = 0; int aligned_width = 0, size = 0; @@ -280,17 +349,23 @@ static int calculate_yuv_offset_and_stride(int format, int width, int height, in aligned_height = ALIGN(height, 32); aligned_width = ALIGN(width, 128); size = aligned_width * aligned_height; - *offset = ALIGN(size,8192); - *yStride = aligned_width; - *uvStride = aligned_width; + yuvInfo.plane1_offset = ALIGN(size,8192); + yuvInfo.yStride = aligned_width; + yuvInfo.plane1_stride = aligned_width; break; } case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: case HAL_PIXEL_FORMAT_YCrCb_420_SP: { aligned_width = ALIGN(width, 32); - *offset = aligned_width * height; - *yStride = aligned_width; - *uvStride = aligned_width; + yuvInfo.yStride = aligned_width; + yuvInfo.plane1_stride = aligned_width; + if (HAL_PIXEL_FORMAT_NV12_ENCODEABLE == format) { + // The encoder requires a 2K aligned chroma offset + yuvInfo.plane1_offset = ALIGN(aligned_width * height, 2048); + } else + yuvInfo.plane1_offset = aligned_width * height; + break; } default: { @@ -302,15 +377,20 @@ static int calculate_yuv_offset_and_stride(int format, int width, int height, in /** create C2D surface from copybit image */ static int set_image(int device_fd, uint32 surfaceId, const struct copybit_image_t *rhs, int *cformat, uint32_t *mapped, - const bool isPremultipliedAlpha) + const eC2DFlags flags) { struct private_handle_t* handle = (struct private_handle_t*)rhs->handle; C2D_SURFACE_TYPE surfaceType; int status = COPYBIT_SUCCESS; - *cformat = get_format(rhs->format); + if (flags & FLAGS_YUV_DESTINATION) { + *cformat = get_c2d_format_for_yuv_destination(rhs->format); + } else { + *cformat = get_format(rhs->format); + } + if(*cformat == -EINVAL) { - LOGE("%s: invalid format", __func__); + LOGE("%s: invalid format", __FUNCTION__); return -EINVAL; } @@ -322,6 +402,7 @@ static int set_image(int device_fd, uint32 surfaceId, const struct copybit_image if (handle->gpuaddr == 0) { handle->gpuaddr = c2d_get_gpuaddr(device_fd, handle); if(!handle->gpuaddr) { + LOGE("%s: c2d_get_gpuaddr failed", __FUNCTION__); return COPYBIT_FAILURE; } *mapped = 1; @@ -337,28 +418,31 @@ static int set_image(int device_fd, uint32 surfaceId, const struct copybit_image surfaceDef.phys = (void*) handle->gpuaddr; surfaceDef.buffer = (void*) (handle->base); - surfaceDef.format = *cformat | (isPremultipliedAlpha ? C2D_FORMAT_PREMULTIPLIED : 0); + surfaceDef.format = *cformat | ((flags & FLAGS_PREMULTIPLIED_ALPHA) ? C2D_FORMAT_PREMULTIPLIED : 0); surfaceDef.width = rhs->w; surfaceDef.height = rhs->h; surfaceDef.stride = ALIGN(((surfaceDef.width * c2diGetBpp(surfaceDef.format))>>3), 32); if(LINK_c2dUpdateSurface( surfaceId,C2D_TARGET | C2D_SOURCE, surfaceType, &surfaceDef)) { - LOGE("%s: RGB Surface c2dUpdateSurface ERROR", __func__); + LOGE("%s: RGB Surface c2dUpdateSurface ERROR", __FUNCTION__); goto error; status = COPYBIT_FAILURE; } } else if (is_supported_yuv_format(rhs->format) == COPYBIT_SUCCESS) { C2D_YUV_SURFACE_DEF surfaceDef; - int offset = 0; - int yStride = 0; - int uvStride = 0; memset(&surfaceDef, 0, sizeof(surfaceDef)); surfaceType = (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS); surfaceDef.format = *cformat; - status = calculate_yuv_offset_and_stride(rhs->format, rhs->w, rhs->h, &offset, &yStride, &uvStride); + bufferInfo info; + info.width = rhs->w; + info.height = rhs->h; + info.format = rhs->format; + + yuvPlaneInfo yuvInfo; + status = calculate_yuv_offset_and_stride(info, yuvInfo); if(status != COPYBIT_SUCCESS) { - LOGE("calculate_yuv_offset_and_stride error"); + LOGE("%s: calculate_yuv_offset_and_stride error", __FUNCTION__); goto error; } @@ -366,19 +450,24 @@ static int set_image(int device_fd, uint32 surfaceId, const struct copybit_image surfaceDef.height = rhs->h; surfaceDef.plane0 = (void*) (handle->base); surfaceDef.phys0 = (void*) (handle->gpuaddr); - surfaceDef.stride0 = yStride; + surfaceDef.stride0 = yuvInfo.yStride; - surfaceDef.plane1 = (void*) (handle->base + offset); - surfaceDef.phys1 = (void*) (handle->gpuaddr + offset); - surfaceDef.stride1 = uvStride; + surfaceDef.plane1 = (void*) (handle->base + yuvInfo.plane1_offset); + surfaceDef.phys1 = (void*) (handle->gpuaddr + yuvInfo.plane1_offset); + surfaceDef.stride1 = yuvInfo.plane1_stride; + if (3 == get_num_planes(rhs->format)) { + surfaceDef.plane2 = (void*) (handle->base + yuvInfo.plane2_offset); + surfaceDef.phys2 = (void*) (handle->gpuaddr + yuvInfo.plane2_offset); + surfaceDef.stride2 = yuvInfo.plane2_stride; + } if(LINK_c2dUpdateSurface( surfaceId,C2D_TARGET | C2D_SOURCE, surfaceType, &surfaceDef)) { - LOGE("%s: YUV Surface c2dUpdateSurface ERROR", __func__); + LOGE("%s: YUV Surface c2dUpdateSurface ERROR", __FUNCTION__); goto error; status = COPYBIT_FAILURE; } } else { - LOGE("%s: invalid format %x", __func__, rhs->format); + LOGE("%s: invalid format 0x%x", __FUNCTION__, rhs->format); goto error; status = COPYBIT_FAILURE; } @@ -427,7 +516,7 @@ static int set_src_image(int device_fd, uint32 *surfaceId, const struct copybit_ surfaceDef.stride = ALIGN(((surfaceDef.width * c2diGetBpp(surfaceDef.format))>>3), 32); if(LINK_c2dCreateSurface( surfaceId, C2D_TARGET, surfaceType,(void*)&surfaceDef)) { - LOGE("%s: LINK_c2dCreateSurface error", __func__); + LOGE("%s: LINK_c2dCreateSurface error", __FUNCTION__); status = COPYBIT_FAILURE; goto error; } @@ -441,9 +530,15 @@ static int set_src_image(int device_fd, uint32 *surfaceId, const struct copybit_ surfaceType = (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS); surfaceDef.format = get_format(rhs->format); - status = calculate_yuv_offset_and_stride(rhs->format, rhs->w, rhs->h, &offset, &yStride, &uvStride); + bufferInfo info; + info.width = rhs->w; + info.height = rhs->h; + info.format = rhs->format; + + yuvPlaneInfo yuvInfo; + status = calculate_yuv_offset_and_stride(info, yuvInfo); if(status != COPYBIT_SUCCESS) { - LOGE("calculate_yuv_offset_and_stride error"); + LOGE("%s: calculate_yuv_offset_and_stride error", __FUNCTION__); goto error; } @@ -451,11 +546,11 @@ static int set_src_image(int device_fd, uint32 *surfaceId, const struct copybit_ surfaceDef.height = rhs->h; surfaceDef.plane0 = (void*) (handle->base); surfaceDef.phys0 = (void*) handle->gpuaddr; - surfaceDef.stride0 = yStride; + surfaceDef.stride0 = yuvInfo.yStride; - surfaceDef.plane1 = (void*) (handle->base + offset); - surfaceDef.phys1 = (void*) (handle->gpuaddr + offset); - surfaceDef.stride1 = uvStride; + surfaceDef.plane1 = (void*) (handle->base + yuvInfo.plane1_offset); + surfaceDef.phys1 = (void*) (handle->gpuaddr + yuvInfo.plane1_offset); + surfaceDef.stride1 = yuvInfo.plane1_stride; if(LINK_c2dCreateSurface( surfaceId, C2D_TARGET | C2D_SOURCE, surfaceType, (void*)&surfaceDef)) { LOGE("%s: YUV surface LINK_c2dCreateSurface error", __func__); @@ -463,7 +558,7 @@ static int set_src_image(int device_fd, uint32 *surfaceId, const struct copybit_ goto error; } } else { - LOGE("%s: Invalid format %x", __func__, rhs->format); + LOGE("%s: Invalid format 0x%x", __FUNCTION__, rhs->format); status = COPYBIT_FAILURE; } @@ -598,7 +693,7 @@ static int msm_copybit(struct copybit_context_t *dev, blitlist *list, uint32 tar if(LINK_c2dDraw(target,dev->trg_transform, 0x0, 0, 0, list->blitObjects, list->count)) { - LOGE("%s: LINK_c2dDraw ERROR"); + LOGE("%s: LINK_c2dDraw ERROR", __FUNCTION__); return COPYBIT_FAILURE; } @@ -615,7 +710,7 @@ static int set_parameter_copybit( { struct copybit_context_t* ctx = (struct copybit_context_t*)dev; if (!ctx) { - LOGE("%s: null context", __func__); + LOGE("%s: null context", __FUNCTION__); return -EINVAL; } @@ -746,20 +841,20 @@ static int stretch_copybit_internal( memset(&list, 0, sizeof(list)); int cformat; c2d_ts_handle timestamp; - uint32 surface_index = 0; + uint32 src_surface_index = 0, dst_surface_index = 0; if (!ctx) { - LOGE("%s: null context error", __func__); + LOGE("%s: null context error", __FUNCTION__); return -EINVAL; } if (src->w > MAX_DIMENSION || src->h > MAX_DIMENSION) { - LOGE("%s: src dimension error", __func__); + LOGE("%s: src dimension error", __FUNCTION__); return -EINVAL; } if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION) { - LOGE("%s : dst dimension error dst w %d h %d", __func__, dst->w, dst->h); + LOGE("%s : dst dimension error dst w %d h %d", __FUNCTION__, dst->w, dst->h); return -EINVAL; } @@ -768,22 +863,63 @@ static int stretch_copybit_internal( struct copybit_rect_t clip; list.count = 0; - status = set_image(ctx->g12_device_fd, ctx->dst, dst, &cformat, &trg_mapped, ctx->isPremultipliedAlpha); + if (is_valid_destination_format(dst->format) == COPYBIT_FAILURE) { + LOGE("%s: Invalid destination format format = 0x%x", __FUNCTION__, dst->format); + return COPYBIT_FAILURE; + } + + bool isYUVDestination = false; + if (is_supported_rgb_format(dst->format) == COPYBIT_SUCCESS) { + dst_surface_index = RGB_SURFACE; + } else if (is_supported_yuv_format(dst->format) == COPYBIT_SUCCESS) { + isYUVDestination = true; + int num_planes = get_num_planes(dst->format); + if (num_planes == 2) { + dst_surface_index = YUV_SURFACE_2_PLANES; + } else if (num_planes == 3) { + dst_surface_index = YUV_SURFACE_3_PLANES; + } else { + LOGE("%s: dst number of YUV planes is invalid dst format = 0x%x", + __FUNCTION__, dst->format); + return COPYBIT_FAILURE; + } + } else { + LOGE("%s: Invalid dst surface format 0x%x", __FUNCTION__, dst->format); + return COPYBIT_FAILURE; + } + + + int flags = 0; + flags |= (ctx->isPremultipliedAlpha) ? FLAGS_PREMULTIPLIED_ALPHA : 0; + flags |= (isYUVDestination) ? FLAGS_YUV_DESTINATION : 0; + + status = set_image(ctx->g12_device_fd, ctx->dst[dst_surface_index], dst, &cformat, + &trg_mapped, (eC2DFlags)flags); if(status) { LOGE("%s: set_image error", __func__); return COPYBIT_FAILURE; } if(is_supported_rgb_format(src->format) == COPYBIT_SUCCESS) { - surface_index = RGB_SURFACE; + src_surface_index = RGB_SURFACE; } else if (is_supported_yuv_format(src->format) == COPYBIT_SUCCESS) { - surface_index = YUV_SURFACE; + int num_planes = get_num_planes(src->format); + if (num_planes == 2) { + src_surface_index = YUV_SURFACE_2_PLANES; + } else if (num_planes == 3) { + src_surface_index = YUV_SURFACE_3_PLANES; + } else { + LOGE("%s: src number of YUV planes is invalid src format = 0x%x", + __FUNCTION__, src->format); + return -EINVAL; + } } else { LOGE("%s: Invalid source surface format %x", __func__, src->format); return -EINVAL; } - status = set_image(ctx->g12_device_fd, ctx->src[surface_index], src, &cformat, &src_mapped, ctx->isPremultipliedAlpha); + status = set_image(ctx->g12_device_fd, ctx->src[src_surface_index], src, &cformat, + &src_mapped, (eC2DFlags)flags); if(status) { LOGE("%s: set_src_image error", __func__); return COPYBIT_FAILURE; @@ -794,8 +930,8 @@ static int stretch_copybit_internal( ctx->blitState.config_mask &= ~C2D_ALPHA_BLEND_NONE; if(!(ctx->blitState.global_alpha)) { // src alpha is zero - unset_image(ctx->g12_device_fd, ctx->src[surface_index], src, src_mapped); - unset_image(ctx->g12_device_fd, ctx->dst, dst, trg_mapped); + unset_image(ctx->g12_device_fd, ctx->src[src_surface_index], src, src_mapped); + unset_image(ctx->g12_device_fd, ctx->dst[dst_surface_index], dst, trg_mapped); return status; } } else { @@ -808,7 +944,7 @@ static int stretch_copybit_internal( ctx->blitState.config_mask |= C2D_ALPHA_BLEND_NONE; } - ctx->blitState.surface_id = ctx->src[surface_index]; + ctx->blitState.surface_id = ctx->src[src_surface_index]; while ((status == 0) && region->next(region, &clip)) { req = &(list.blitObjects[list.count]); @@ -817,21 +953,21 @@ static int stretch_copybit_internal( set_rects(ctx, req, dst_rect, src_rect, &clip); if (++list.count == maxCount) { - status = msm_copybit(ctx, &list, ctx->dst); + status = msm_copybit(ctx, &list, ctx->dst[dst_surface_index]); list.count = 0; } } if ((status == 0) && list.count) { - status = msm_copybit(ctx, &list, ctx->dst); + status = msm_copybit(ctx, &list, ctx->dst[dst_surface_index]); } - if(LINK_c2dFinish(ctx->dst)) { - LOGE("%s: LINK_c2dFinish ERROR", __func__); + if(LINK_c2dFinish(ctx->dst[dst_surface_index])) { + LOGE("%s: LINK_c2dFinish ERROR", __FUNCTION__); } - unset_image(ctx->g12_device_fd, ctx->src[surface_index], src, src_mapped); - unset_image(ctx->g12_device_fd, ctx->dst, dst, trg_mapped); + unset_image(ctx->g12_device_fd, ctx->src[src_surface_index], src, src_mapped); + unset_image(ctx->g12_device_fd, ctx->dst[dst_surface_index], dst, trg_mapped); ctx->isPremultipliedAlpha = false; return status; } @@ -866,8 +1002,8 @@ static int close_copybit(struct hw_device_t *dev) { struct copybit_context_t* ctx = (struct copybit_context_t*)dev; if (ctx) { - LINK_c2dDestroySurface(ctx->dst); - for(int i = 0; i dst[i]); LINK_c2dDestroySurface(ctx->src[i]); } @@ -903,13 +1039,18 @@ static int open_copybit(const struct hw_module_t* module, const char* name, ctx = (struct copybit_context_t *)malloc(sizeof(struct copybit_context_t)); if(!ctx) { - LOGE("%s: malloc failed", __func__); + LOGE("%s: malloc failed", __FUNCTION__); return COPYBIT_FAILURE; } /* initialize drawstate */ memset(ctx, 0, sizeof(*ctx)); + for (int i=0; i< NUM_SURFACES; i++) { + ctx->dst[i] = -1; + ctx->src[i] = -1; + } + ctx->libc2d2 = ::dlopen("libC2D2.so", RTLD_NOW); if (!ctx->libc2d2) { LOGE("FATAL ERROR: could not dlopen libc2d2.so: %s", dlerror()); @@ -929,11 +1070,11 @@ static int open_copybit(const struct hw_module_t* module, const char* name, *(void **)&LINK_c2dDestroySurface = ::dlsym(ctx->libc2d2, "c2dDestroySurface"); - if(!LINK_c2dCreateSurface || !LINK_c2dUpdateSurface || !LINK_c2dReadSurface + if (!LINK_c2dCreateSurface || !LINK_c2dUpdateSurface || !LINK_c2dReadSurface || !LINK_c2dDraw || !LINK_c2dFlush || !LINK_c2dWaitTimestamp || !LINK_c2dFinish || !LINK_c2dDestroySurface) { - LOGE("%s: dlsym ERROR", __func__); - goto error1; + LOGE("%s: dlsym ERROR", __FUNCTION__); + goto error; } ctx->device.common.tag = HARDWARE_DEVICE_TAG; @@ -947,9 +1088,9 @@ static int open_copybit(const struct hw_module_t* module, const char* name, ctx->blitState.config_mask = C2D_NO_BILINEAR_BIT | C2D_NO_ANTIALIASING_BIT; ctx->trg_transform = C2D_TARGET_ROTATE_0; ctx->g12_device_fd = open(G12_DEVICE_NAME, O_RDWR | O_SYNC); - if(ctx->g12_device_fd < 0) { - LOGE("%s: g12_device_fd open failed", __func__); - goto error1; + if (ctx->g12_device_fd < 0) { + LOGE("%s: g12_device_fd open failed", __FUNCTION__); + goto error; } /* Create RGB Surface */ @@ -959,19 +1100,21 @@ static int open_copybit(const struct hw_module_t* module, const char* name, surfDefinition.width = 1; surfDefinition.height = 1; surfDefinition.format = C2D_COLOR_FORMAT_8888_ARGB; - - if(LINK_c2dCreateSurface(&ctx->dst,C2D_TARGET | C2D_SOURCE, + if (LINK_c2dCreateSurface(&(ctx->dst[RGB_SURFACE]), C2D_TARGET | C2D_SOURCE, (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS), &surfDefinition)) { - LOGE("%s: create ctx->dst failed", __func__); - goto error2; + LOGE("%s: create ctx->dst[RGB_SURFACE] failed", __FUNCTION__); + ctx->dst[RGB_SURFACE] = -1; + goto error; } - if(LINK_c2dCreateSurface(&(ctx->src[RGB_SURFACE]), C2D_TARGET | C2D_SOURCE, + + if (LINK_c2dCreateSurface(&(ctx->src[RGB_SURFACE]), C2D_TARGET | C2D_SOURCE, (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS), &surfDefinition)) { - LOGE("%s: create ctx->src[RGB_SURFACE] failed", __func__); - goto error3; + LOGE("%s: create ctx->src[RGB_SURFACE] failed", __FUNCTION__); + ctx->src[RGB_SURFACE] = -1; + goto error; } /* Create YUV source surface */ @@ -987,11 +1130,41 @@ static int open_copybit(const struct hw_module_t* module, const char* name, yuvSurfaceDef.phys1 = (void*) 0xaaaaaaaa; yuvSurfaceDef.stride1 = 4; - if(LINK_c2dCreateSurface(&(ctx->src[YUV_SURFACE]),C2D_TARGET | C2D_SOURCE, + if (LINK_c2dCreateSurface(&(ctx->src[YUV_SURFACE_2_PLANES]),C2D_TARGET | C2D_SOURCE, (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS), &yuvSurfaceDef)) { - LOGE("%s: create ctx->src[YUV_SURFACE] failed", __func__); - goto error4; + LOGE("%s: create ctx->src[YUV_SURFACE_2_PLANES] failed", __FUNCTION__); + ctx->src[YUV_SURFACE_2_PLANES] = -1; + goto error; + } + + if (LINK_c2dCreateSurface(&(ctx->dst[YUV_SURFACE_2_PLANES]),C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS), + &yuvSurfaceDef)) { + LOGE("%s: create ctx->dst[YUV_SURFACE_2_PLANES] failed", __FUNCTION__); + ctx->dst[YUV_SURFACE_2_PLANES] = -1; + goto error; + } + + yuvSurfaceDef.format = C2D_COLOR_FORMAT_420_YV12; + yuvSurfaceDef.plane2 = (void*)0xaaaaaaaa; + yuvSurfaceDef.phys2 = (void*) 0xaaaaaaaa; + yuvSurfaceDef.stride2 = 4; + + if (LINK_c2dCreateSurface(&(ctx->src[YUV_SURFACE_3_PLANES]),C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS), + &yuvSurfaceDef)) { + LOGE("%s: create ctx->src[YUV_SURFACE_3_PLANES] failed", __FUNCTION__); + ctx->src[YUV_SURFACE_3_PLANES] = -1; + goto error; + } + + if (LINK_c2dCreateSurface(&(ctx->dst[YUV_SURFACE_3_PLANES]),C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS), + &yuvSurfaceDef)) { + LOGE("%s: create ctx->dst[YUV_SURFACE_3_PLANES] failed", __FUNCTION__); + ctx->dst[YUV_SURFACE_3_PLANES] = -1; + goto error; } *device = &ctx->device.common; @@ -1002,11 +1175,11 @@ static int open_copybit(const struct hw_module_t* module, const char* name, i++; } if (fd < 0) - goto error5; + goto error; struct fb_var_screeninfo info; if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) - goto error6; + goto error; ctx->fb_width = info.xres; ctx->fb_height = info.yres; @@ -1014,21 +1187,29 @@ static int open_copybit(const struct hw_module_t* module, const char* name, ctx->isPremultipliedAlpha = false; return status; -error6: - close(fd); - fd = -1; -error5: - LINK_c2dDestroySurface(ctx->src[YUV_SURFACE]); -error4: - LINK_c2dDestroySurface(ctx->src[RGB_SURFACE]); -error3: - LINK_c2dDestroySurface(ctx->dst); -error2: - close(ctx->g12_device_fd); -error1: - ::dlclose(ctx->libc2d2); error: - free(ctx); + if (fd >= 0) { + close(fd); + fd = -1; + } + + for (int i = 0; isrc[i])) { + LINK_c2dDestroySurface(ctx->src[i]); + ctx->src[i] = -1; + } + if (-1 != (ctx->dst[i])) { + LINK_c2dDestroySurface(ctx->dst[i]); + ctx->dst[i] = -1; + } + } + if (ctx->g12_device_fd >= 0) { + close(ctx->g12_device_fd); + } + if (ctx->libc2d2) + ::dlclose(ctx->libc2d2); + if (ctx) + free(ctx); status = COPYBIT_FAILURE; *device = NULL; From 90f0fc7201bff9823ed8ac63873be0bdec7ccb9b Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Tue, 6 Dec 2011 12:58:20 -0800 Subject: [PATCH 21/33] libcopybit: Add support for setting the Framebuffer info. Add support to set the framebuffer width and height in the copybit context. This parameter will be set for composition using c2d where the c2d target is calculated based on the framebuffer width and height. Change-Id: Ica0f7622bed305c0f56dd0a16b35406c28600fd8 --- libcopybit/copybit.h | 6 +++- libcopybit/copybit_c2d.cpp | 57 +++++++++++++++----------------------- 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/libcopybit/copybit.h b/libcopybit/copybit.h index 920f858..e6c55e0 100644 --- a/libcopybit/copybit.h +++ b/libcopybit/copybit.h @@ -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) */ diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp index e3d6308..93f2759 100644 --- a/libcopybit/copybit_c2d.cpp +++ b/libcopybit/copybit_c2d.cpp @@ -642,22 +642,26 @@ static void set_rects(struct copybit_context_t *ctx, const struct copybit_rect_t *src, const struct copybit_rect_t *scissor) { - + // Set the target rect. if((ctx->trg_transform & C2D_TARGET_ROTATE_90) && (ctx->trg_transform & C2D_TARGET_ROTATE_180)) { /* target rotation is 270 */ c2dObject->target_rect.x = (dst->t)<<16; - c2dObject->target_rect.y = (ALIGN(ctx->fb_width,32) - (dst->r))<<16; + c2dObject->target_rect.y = ctx->fb_width?(ALIGN(ctx->fb_width,32)- dst->r):dst->r; + c2dObject->target_rect.y = c2dObject->target_rect.y<<16; c2dObject->target_rect.height = ((dst->r) - (dst->l))<<16; c2dObject->target_rect.width = ((dst->b) - (dst->t))<<16; } else if(ctx->trg_transform & C2D_TARGET_ROTATE_90) { - c2dObject->target_rect.x = (ctx->fb_height - dst->b)<<16; + c2dObject->target_rect.x = ctx->fb_height?(ctx->fb_height - dst->b):dst->b; + c2dObject->target_rect.x = c2dObject->target_rect.x<<16; c2dObject->target_rect.y = (dst->l)<<16; c2dObject->target_rect.height = ((dst->r) - (dst->l))<<16; c2dObject->target_rect.width = ((dst->b) - (dst->t))<<16; } else if(ctx->trg_transform & C2D_TARGET_ROTATE_180) { - c2dObject->target_rect.y = (ctx->fb_height - dst->b)<<16; - c2dObject->target_rect.x = (ALIGN(ctx->fb_width,32) - dst->r)<<16; + c2dObject->target_rect.y = ctx->fb_height?(ctx->fb_height - dst->b):dst->b; + c2dObject->target_rect.y = c2dObject->target_rect.y<<16; + c2dObject->target_rect.x = ctx->fb_width?(ALIGN(ctx->fb_width,32) - dst->r):dst->r; + c2dObject->target_rect.x = c2dObject->target_rect.x<<16; c2dObject->target_rect.height = ((dst->b) - (dst->t))<<16; c2dObject->target_rect.width = ((dst->r) - (dst->l))<<16; } else { @@ -668,17 +672,18 @@ static void set_rects(struct copybit_context_t *ctx, } c2dObject->config_mask |= C2D_TARGET_RECT_BIT; + // Set the source rect c2dObject->source_rect.x = (src->l)<<16; c2dObject->source_rect.y = (src->t)<<16; c2dObject->source_rect.height = ((src->b) - (src->t))<<16; c2dObject->source_rect.width = ((src->r) - (src->l))<<16; c2dObject->config_mask |= C2D_SOURCE_RECT_BIT; + // Set the scissor rect c2dObject->scissor_rect.x = scissor->l; c2dObject->scissor_rect.y = scissor->t; c2dObject->scissor_rect.height = (scissor->b) - (scissor->t); c2dObject->scissor_rect.width = (scissor->r) - (scissor->l); - c2dObject->config_mask |= C2D_SCISSOR_RECT_BIT; } @@ -761,6 +766,12 @@ static int set_parameter_copybit( (value == COPYBIT_ENABLE) ? ctx->isPremultipliedAlpha = true : ctx->isPremultipliedAlpha = false; break; + case COPYBIT_FRAMEBUFFER_WIDTH: + ctx->fb_width = value; + break; + case COPYBIT_FRAMEBUFFER_HEIGHT: + ctx->fb_height = value; + break; default: LOGE("%s: default case", __func__); return -EINVAL; @@ -969,6 +980,8 @@ static int stretch_copybit_internal( unset_image(ctx->g12_device_fd, ctx->src[src_surface_index], src, src_mapped); unset_image(ctx->g12_device_fd, ctx->dst[dst_surface_index], dst, trg_mapped); ctx->isPremultipliedAlpha = false; + ctx->fb_width = 0; + ctx->fb_height = 0; return status; } @@ -1028,13 +1041,6 @@ static int open_copybit(const struct hw_module_t* module, const char* name, C2D_RGB_SURFACE_DEF surfDefinition = {0}; C2D_YUV_SURFACE_DEF yuvSurfaceDef = {0} ; struct copybit_context_t *ctx; - char const * const device_template[] = { - "/dev/graphics/fb%u", - "/dev/fb%u", - 0 }; - - int fd = -1; - int i=0; char fbName[64]; ctx = (struct copybit_context_t *)malloc(sizeof(struct copybit_context_t)); @@ -1167,32 +1173,13 @@ static int open_copybit(const struct hw_module_t* module, const char* name, goto error; } - *device = &ctx->device.common; - - while ((fd==-1) && device_template[i]) { - snprintf(fbName, 64, device_template[i], 0); - fd = open(fbName, O_RDWR, 0); - i++; - } - if (fd < 0) - goto error; - - struct fb_var_screeninfo info; - if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) - goto error; - - ctx->fb_width = info.xres; - ctx->fb_height = info.yres; - close(fd); + ctx->fb_width = 0; + ctx->fb_height = 0; ctx->isPremultipliedAlpha = false; + *device = &ctx->device.common; return status; error: - if (fd >= 0) { - close(fd); - fd = -1; - } - for (int i = 0; isrc[i])) { LINK_c2dDestroySurface(ctx->src[i]); From c421c6ac191326dbd79b60aa47eda3daf88ba890 Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Tue, 6 Dec 2011 12:14:55 +0530 Subject: [PATCH 22/33] gralloc: Limit fallback case for SMI For pmem, do not fall back to the ADSP heap if SMI was requested explicitly Change-Id: I31d85aa7bef3db53ca9ba108170df7ef4841843b --- libgralloc/alloc_controller.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp index 53f4354..b7ec509 100644 --- a/libgralloc/alloc_controller.cpp +++ b/libgralloc/alloc_controller.cpp @@ -164,6 +164,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) || @@ -179,8 +181,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"); } } } From c2e6b1f62eb4c0f02d65582336cc904e996794cd Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Wed, 7 Dec 2011 10:51:40 +0530 Subject: [PATCH 23/33] display: Use bypass only for contiguous memory Since composition bypass uses MDP overlays, which need physically contiguous memory, we cannot use bypass in cases where the buffers are using ashmem or other virtual memory. Hence, avoid bypass in such cases. Change-Id: I5c6d20e68e15719295373a1b0f3b930536336c43 --- libgralloc/alloc_controller.cpp | 19 +++++++++++++++---- libgralloc/gralloc_priv.h | 1 + libhwcomposer/hwcomposer.cpp | 24 ++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp index b7ec509..a549766 100644 --- a/libgralloc/alloc_controller.cpp +++ b/libgralloc/alloc_controller.cpp @@ -88,6 +88,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 && @@ -105,8 +106,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; } @@ -252,8 +259,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 +278,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; diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 0e45e4a..6f109a1 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -284,6 +284,7 @@ struct private_handle_t { PRIV_FLAGS_NEEDS_FLUSH = 0x00000020, PRIV_FLAGS_DO_NOT_FLUSH = 0x00000040, PRIV_FLAGS_SW_LOCK = 0x00000080, + PRIV_FLAGS_NONCONTIGUOUS_MEM = 0x00000100, }; // file-descriptors diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index 46962af..6905453 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -546,9 +546,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(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) { @@ -559,6 +576,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); From 2987491ac850dc2aa5878bd202e33c24484ad3cb Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Wed, 7 Dec 2011 12:47:14 -0800 Subject: [PATCH 24/33] liboverlay: Add support for interlaced content in updateOverlaySource. UpdateOverlay source didn't have any support for interlaced content. Add the required support. Create a new function to check if the content is interlaced. Change-Id: Ie47b7669461f773b55c71cad6978fc1c8cf4e91b --- liboverlay/overlayLib.cpp | 25 ++++++++++++++++++++----- liboverlay/overlayLib.h | 1 + 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/liboverlay/overlayLib.cpp b/liboverlay/overlayLib.cpp index 5245fc2..6f2c604 100755 --- a/liboverlay/overlayLib.cpp +++ b/liboverlay/overlayLib.cpp @@ -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, @@ -970,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 @@ -1051,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); @@ -1072,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 diff --git a/liboverlay/overlayLib.h b/liboverlay/overlayLib.h index 0a502ea..1448f83 100755 --- a/liboverlay/overlayLib.h +++ b/liboverlay/overlayLib.h @@ -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); From 27774b1a66e1f77b5f7915f17ae5365e79a4be27 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Tue, 6 Dec 2011 12:22:16 -0800 Subject: [PATCH 25/33] libhwcomposer: Set the Framebuffer info for copybit composition. Invoke copybit's set parameter call to set the framebuffer width and height. Change-Id: I735772e21b9fead48686fac3371b6b93156ece8a --- libhwcomposer/hwcomposer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index 6905453..298dc3c 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -1039,6 +1039,8 @@ 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); From 18e73bc5c74846fd1ab907539e70935362972394 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Wed, 7 Dec 2011 13:02:35 -0800 Subject: [PATCH 26/33] Display: Add libQcomUI Add libQComUI which is used to perform operations specified by SurfaceTextures. The operation currently supported by this library is SET_BUFFER_SIZE which deallocates and reallocates memory if the size allocated for the buffer does not match the size requested by the client. Change-Id: I370b94a91f5acf373f7040742aad7c2e7bb586fe --- Android.mk | 1 + libqcomui/Android.mk | 16 ++++ libqcomui/qcom_ui.cpp | 174 ++++++++++++++++++++++++++++++++++++++++++ libqcomui/qcom_ui.h | 72 +++++++++++++++++ 4 files changed, 263 insertions(+) create mode 100644 libqcomui/Android.mk create mode 100644 libqcomui/qcom_ui.cpp create mode 100644 libqcomui/qcom_ui.h diff --git a/Android.mk b/Android.mk index 373fbfc..565ddf1 100644 --- a/Android.mk +++ b/Android.mk @@ -1,4 +1,5 @@ #Enables the listed display HAL modules display-hals := libhwcomposer liboverlay libgralloc libgenlock libcopybit libtilerenderer +display-hals += libqcomui include $(call all-named-subdir-makefiles,$(display-hals)) diff --git a/libqcomui/Android.mk b/libqcomui/Android.mk new file mode 100644 index 0000000..270de84 --- /dev/null +++ b/libqcomui/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + qcom_ui.cpp + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libcutils \ + libmemalloc + +LOCAL_C_INCLUDES := $(TOP)/hardware/qcom/display/libgralloc +LOCAL_CFLAGS := -DLOG_TAG=\"libQcomUI\" +LOCAL_MODULE := libQcomUI +LOCAL_MODULE_TAGS := optional +include $(BUILD_SHARED_LIBRARY) diff --git a/libqcomui/qcom_ui.cpp b/libqcomui/qcom_ui.cpp new file mode 100644 index 0000000..9f843dd --- /dev/null +++ b/libqcomui/qcom_ui.cpp @@ -0,0 +1,174 @@ +/* + * 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 +#include +#include +#include +#include +#include + +using gralloc::IMemAlloc; +using gralloc::IonController; +using gralloc::alloc_data; +using android::sp; + +namespace { + + static android::sp 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 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; + 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(buffer_handle); + if (hnd->size < size) { + return reallocate_memory(hnd, size, usage); + } + + return 0; +} + + + + diff --git a/libqcomui/qcom_ui.h b/libqcomui/qcom_ui.h new file mode 100644 index 0000000..b55ff4a --- /dev/null +++ b/libqcomui/qcom_ui.h @@ -0,0 +1,72 @@ +/* + * 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 + +/* + * Qcom specific Native Window perform operations + */ +enum { + NATIVE_WINDOW_SET_BUFFERS_SIZE = 0x10000000, +}; + +/* + * 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); +#endif // INCLUDE_LIBQCOM_UI From be32078a404a7bf6b326bcbacbc260900542f87b Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Fri, 9 Dec 2011 15:30:49 -0800 Subject: [PATCH 27/33] libQcomUI: Add support for updating the buffer geometry Add support for updating the buffer geometry without any reallocation of memory. The buffer geometry is updated in the GraphicBuffer as well as in the buffer handle. Change-Id: I3fdb4f6a737277ab63fcbdb42e9c955ea7471760 --- libqcomui/Android.mk | 5 +-- libqcomui/qcom_ui.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++- libqcomui/qcom_ui.h | 42 ++++++++++++++++++++++- 3 files changed, 123 insertions(+), 4 deletions(-) diff --git a/libqcomui/Android.mk b/libqcomui/Android.mk index 270de84..2b786d9 100644 --- a/libqcomui/Android.mk +++ b/libqcomui/Android.mk @@ -7,9 +7,10 @@ LOCAL_SRC_FILES := \ LOCAL_SHARED_LIBRARIES := \ libutils \ libcutils \ - libmemalloc + libmemalloc \ + libui -LOCAL_C_INCLUDES := $(TOP)/hardware/qcom/display/libgralloc +LOCAL_C_INCLUDES := $(TOP)/hardware/qcom/display/libgralloc \ LOCAL_CFLAGS := -DLOG_TAG=\"libQcomUI\" LOCAL_MODULE := libQcomUI LOCAL_MODULE_TAGS := optional diff --git a/libqcomui/qcom_ui.cpp b/libqcomui/qcom_ui.cpp index 9f843dd..df82cae 100644 --- a/libqcomui/qcom_ui.cpp +++ b/libqcomui/qcom_ui.cpp @@ -108,6 +108,9 @@ int getNumberOfArgsForOperation(int 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; }; @@ -169,6 +172,81 @@ int checkBuffer(native_handle_t *buffer_handle, int size, int 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 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; +} diff --git a/libqcomui/qcom_ui.h b/libqcomui/qcom_ui.h index b55ff4a..0b78f47 100644 --- a/libqcomui/qcom_ui.h +++ b/libqcomui/qcom_ui.h @@ -31,12 +31,31 @@ #define INCLUDE_LIBQCOM_UI #include +#include + +using android::sp; +using android::GraphicBuffer; /* * Qcom specific Native Window perform operations */ enum { - NATIVE_WINDOW_SET_BUFFERS_SIZE = 0x10000000, + NATIVE_WINDOW_SET_BUFFERS_SIZE = 0x10000000, + NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY = 0x20000000, +}; + +/* + * 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; + } }; /* @@ -69,4 +88,25 @@ bool isGPUSupportedFormat(int format); * @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 buffer, const qBufGeometry bufGeometry); #endif // INCLUDE_LIBQCOM_UI From 8d7ff87f5c874ea1af716379e9bfbc485ef869ec Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Sun, 11 Dec 2011 15:25:13 -0800 Subject: [PATCH 28/33] libQcomUI: Add support for qcom specific layer flags. Add support for updating the qcom specific layer flags. Add support for getting the per frame HWC flags based on the layer flags. Change-Id: I5f7759a6a7fae6d4f70dd26f380a9b08e48e9475 --- libqcomui/qcom_ui.cpp | 41 ++++++++++++++++++++++++++++++++++++++ libqcomui/qcom_ui.h | 46 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/libqcomui/qcom_ui.cpp b/libqcomui/qcom_ui.cpp index df82cae..9de00e7 100644 --- a/libqcomui/qcom_ui.cpp +++ b/libqcomui/qcom_ui.cpp @@ -249,4 +249,45 @@ int updateBufferGeometry(sp buffer, const qBufGeometry updatedGeo 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; +} diff --git a/libqcomui/qcom_ui.h b/libqcomui/qcom_ui.h index 0b78f47..6744edf 100644 --- a/libqcomui/qcom_ui.h +++ b/libqcomui/qcom_ui.h @@ -44,6 +44,30 @@ enum { 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 */ @@ -109,4 +133,26 @@ bool needNewBuffer(const qBufGeometry currentGeometry, * @param: Updated buffer geometry */ int updateBufferGeometry(sp 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 From b6ca342fac38403028b65284de60592dbe6971d5 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Tue, 6 Dec 2011 12:35:03 -0800 Subject: [PATCH 29/33] libcopybit: Add support for converting to non 32pixel aligned formats. Android YUV formats are aligned to 16pixels, while C2D requires 32pixel aligned. Use a temp buffer to do the conversion. Change-Id: Iff93b56e152460255d480dc703dabbcdb3697995 --- libcopybit/Android.mk | 4 +- libcopybit/copybit_c2d.cpp | 332 ++++++++++++++++++++++++++++-- libcopybit/software_converter.cpp | 139 ++++++++++++- libcopybit/software_converter.h | 27 +++ 4 files changed, 480 insertions(+), 22 deletions(-) diff --git a/libcopybit/Android.mk b/libcopybit/Android.mk index c23ecd8..21afb9d 100644 --- a/libcopybit/Android.mk +++ b/libcopybit/Android.mk @@ -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 += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp index 93f2759..3b4d5f6 100644 --- a/libcopybit/copybit_c2d.cpp +++ b/libcopybit/copybit_c2d.cpp @@ -36,11 +36,14 @@ #include #include #include +#include +#include #include #include #include "c2d2.h" +#include "software_converter.h" #include C2D_STATUS (*LINK_c2dCreateSurface)( uint32 *surface_id, @@ -83,10 +86,7 @@ C2D_STATUS (*LINK_c2dDestroySurface)( uint32 surface_id ); #define G12_DEVICE_NAME "/dev/kgsl-2d0" -#define COPYBIT_SUCCESS 0 -#define COPYBIT_FAILURE -1 #define NUM_SURFACES 3 -#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) enum { RGB_SURFACE, @@ -94,6 +94,11 @@ enum { YUV_SURFACE_3_PLANES }; +enum eConversionType { + CONVERT_TO_ANDROID_FORMAT, + CONVERT_TO_C2D_FORMAT +}; + enum eC2DFlags { FLAGS_PREMULTIPLIED_ALPHA = 1<<0, FLAGS_YUV_DESTINATION = 1<<1 @@ -125,6 +130,11 @@ struct bufferInfo { int format; }; +struct memInfo { + int fd; + size_t size; + int base; +}; struct yuvPlaneInfo { int yStride; //luma stride @@ -298,6 +308,7 @@ static int get_num_planes(int format) switch(format) { case HAL_PIXEL_FORMAT_YCbCr_420_SP: case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: { return 2; } @@ -421,7 +432,8 @@ static int set_image(int device_fd, uint32 surfaceId, const struct copybit_image surfaceDef.format = *cformat | ((flags & FLAGS_PREMULTIPLIED_ALPHA) ? C2D_FORMAT_PREMULTIPLIED : 0); surfaceDef.width = rhs->w; surfaceDef.height = rhs->h; - surfaceDef.stride = ALIGN(((surfaceDef.width * c2diGetBpp(surfaceDef.format))>>3), 32); + int aligned_width = ALIGN(surfaceDef.width,32); + surfaceDef.stride = (aligned_width * c2diGetBpp(surfaceDef.format))>>3; if(LINK_c2dUpdateSurface( surfaceId,C2D_TARGET | C2D_SOURCE, surfaceType, &surfaceDef)) { LOGE("%s: RGB Surface c2dUpdateSurface ERROR", __FUNCTION__); @@ -773,7 +785,7 @@ static int set_parameter_copybit( ctx->fb_height = value; break; default: - LOGE("%s: default case", __func__); + LOGE("%s: default case param=0x%x", __FUNCTION__, name); return -EINVAL; break; } @@ -788,7 +800,7 @@ static int get(struct copybit_device_t *dev, int name) int value; if (!ctx) { - LOGE("%s: null context error", __func__); + LOGE("%s: null context error", __FUNCTION__); return -EINVAL; } @@ -806,7 +818,7 @@ static int get(struct copybit_device_t *dev, int name) value = 1; break; default: - LOGE("%s: default case", __func__); + LOGE("%s: default case param=0x%x", __FUNCTION__, name); value = -EINVAL; } return value; @@ -833,6 +845,171 @@ static int is_alpha(int cformat) return alpha; } +/* Function to check if we need a temporary buffer for the blit. + * This would happen if the requested destination stride and the + * C2D stride do not match. We ignore RGB buffers, since their + * stride is always aligned to 32. + */ +static bool need_temp_buffer(struct copybit_image_t const *img) +{ + if (COPYBIT_SUCCESS == is_supported_rgb_format(img->format)) + return false; + + struct private_handle_t* handle = (struct private_handle_t*)img->handle; + + // The width parameter in the handle contains the aligned_w. We check if we + // need to convert based on this param. YUV formats have bpp=1, so checking + // if the requested stride is aligned should suffice. + if (0 == (handle->width)%32) { + return false; + } + + return true; +} + +/* Function to extract the information from the copybit image and set the corresponding + * values in the bufferInfo struct. + */ +static void populate_buffer_info(struct copybit_image_t const *img, bufferInfo& info) +{ + info.width = img->w; + info.height = img->h; + info.format = img->format; +} + +/* Function to get the required size for a particular format, inorder for C2D to perform + * the blit operation. + */ +static size_t get_size(const bufferInfo& info) +{ + size_t size = 0; + int w = info.width; + int h = info.height; + int aligned_w = ALIGN(w, 32); + switch(info.format) { + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + { + // Chroma for this format is aligned to 2K. + size = ALIGN((aligned_w*h), 2048) + + ALIGN(w/2, 32) * h/2 *2; + size = ALIGN(size, 4096); + } break; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + { + size = aligned_w*h + + ALIGN(w/2, 32) * h/2 *2; + size = ALIGN(size, 4096); + } break; + default: break; + } + return size; +} + +/* Function to allocate memory for the temporary buffer. This memory is + * allocated from Ashmem. It is the caller's responsibility to free this + * memory. + */ +static int get_temp_buffer(const bufferInfo& info, memInfo& mem_info) +{ + // Alloc memory from ashmem + int err = COPYBIT_SUCCESS; + size_t size = get_size(info); + char name[ASHMEM_NAME_LEN]; + snprintf(name, ASHMEM_NAME_LEN, "c2d-buffer-%x",mem_info); + int prot = PROT_READ | PROT_WRITE; + int fd = ashmem_create_region(name, size); + void *base = 0; + if (fd < 0) { + LOGE("%s: couldn't create ashmem (%s)", __FUNCTION__, + strerror(errno)); + return COPYBIT_FAILURE; + } else { + if (ashmem_set_prot_region(fd, prot) < 0) { + LOGE("%s: ashmem_set_prot_region(fd=%d, prot=%x) failed (%s)", + __FUNCTION__, fd, prot, strerror(errno)); + close(fd); + fd = -1; + return COPYBIT_FAILURE; + } else { + base = mmap(0, size, prot, MAP_SHARED|MAP_POPULATE|MAP_LOCKED, fd, 0); + if (base == MAP_FAILED) { + LOGE("%s: alloc mmap(fd=%d, size=%d, prot=%x) failed (%s)", + __FUNCTION__, fd, size, prot, strerror(errno)); + close(fd); + fd = -1; + return COPYBIT_FAILURE; + } + } + } + if (ioctl(fd, ASHMEM_CACHE_INV_RANGE, NULL)) { + LOGE("ASHMEM_CACHE_INV_RANGE failed fd = %d", fd); + } + + // Save the memory info. + mem_info.fd = fd; + mem_info.size = size; + mem_info.base = (int)base; + return err; +} + +/* Function to free the temporary allocated memory.*/ +static void free_temp_image(private_handle_t *hnd) +{ + if (hnd) { + if (0 != hnd->base) { + munmap((void *)hnd->base, hnd->size); + hnd->base = 0; + } + + if (hnd->fd != -1) { + close(hnd->fd); + hnd->fd = -1; + } + } +} + +/* Function to perform the software color conversion. Convert the + * C2D compatible format to the Android compatible format + */ +static int copy_image(private_handle_t *src_handle, + struct copybit_image_t const *rhs, + eConversionType conversionType) +{ + if (src_handle->fd == -1) { + LOGE("%s: src_handle fd is invalid", __FUNCTION__); + return COPYBIT_FAILURE; + } + + // Copy the info. + int ret = COPYBIT_SUCCESS; + switch(rhs->format) { + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + { + if (CONVERT_TO_ANDROID_FORMAT == conversionType) { + return convert_yuv_c2d_to_yuv_android(src_handle, rhs); + } else { + return convert_yuv_android_to_yuv_c2d(src_handle, rhs); + } + + } break; + default: { + LOGE("%s: invalid format 0x%x", __FUNCTION__, rhs->format); + ret = COPYBIT_FAILURE; + } break; + } + return ret; +} + +static void delete_handle(private_handle_t *handle) +{ + if (handle) { + delete handle; + handle = 0; + } +} /** do a stretch blit type operation */ static int stretch_copybit_internal( struct copybit_device_t *dev, @@ -899,15 +1076,49 @@ static int stretch_copybit_internal( return COPYBIT_FAILURE; } + copybit_image_t dst_image; + dst_image.w = dst->w; + dst_image.h = dst->h; + dst_image.format = dst->format; + dst_image.handle = dst->handle; + // Check if we need a temp. copy for the destination. We'd need this the destination + // width is not aligned to 32. This case occurs for YUV formats. RGB formats are + // aligned to 32. + bool needTempDestination = need_temp_buffer(dst); + memInfo mem_info; + bufferInfo dst_info; + populate_buffer_info(dst, dst_info); + private_handle_t* dst_hnd = new private_handle_t(-1, 0, 0, 0, dst_info.format, + dst_info.width, dst_info.height); + if (dst_hnd == NULL) { + LOGE("%s: dst_hnd is null", __FUNCTION__); + return COPYBIT_FAILURE; + } + if (needTempDestination) { + // Create a temp buffer and set that as the destination. + if (COPYBIT_SUCCESS == get_temp_buffer(dst_info, mem_info)) { + dst_hnd->fd = mem_info.fd; + dst_hnd->size = mem_info.size; + dst_hnd->flags = private_handle_t::PRIV_FLAGS_USES_ASHMEM; + dst_hnd->base = mem_info.base; + dst_hnd->offset = 0; + dst_hnd->gpuaddr = 0; + dst_image.handle = dst_hnd; + } + } int flags = 0; flags |= (ctx->isPremultipliedAlpha) ? FLAGS_PREMULTIPLIED_ALPHA : 0; flags |= (isYUVDestination) ? FLAGS_YUV_DESTINATION : 0; - status = set_image(ctx->g12_device_fd, ctx->dst[dst_surface_index], dst, &cformat, - &trg_mapped, (eC2DFlags)flags); + status = set_image(ctx->g12_device_fd, ctx->dst[dst_surface_index], &dst_image, &cformat, + &trg_mapped, (eC2DFlags)flags); if(status) { - LOGE("%s: set_image error", __func__); + LOGE("%s: dst: set_image error", __FUNCTION__); + if (needTempDestination) { + free_temp_image(dst_hnd); + } + delete_handle(dst_hnd); return COPYBIT_FAILURE; } @@ -922,17 +1133,81 @@ static int stretch_copybit_internal( } else { LOGE("%s: src number of YUV planes is invalid src format = 0x%x", __FUNCTION__, src->format); + if (needTempDestination) { + free_temp_image(dst_hnd); + } + delete_handle(dst_hnd); return -EINVAL; } } else { - LOGE("%s: Invalid source surface format %x", __func__, src->format); + LOGE("%s: Invalid source surface format 0x%x", __FUNCTION__, src->format); + if (needTempDestination) { + free_temp_image(dst_hnd); + } + delete_handle(dst_hnd); return -EINVAL; } - status = set_image(ctx->g12_device_fd, ctx->src[src_surface_index], src, &cformat, - &src_mapped, (eC2DFlags)flags); + copybit_image_t src_image; + src_image.w = src->w; + src_image.h = src->h; + src_image.format = src->format; + src_image.handle = src->handle; + + bool needTempSource = need_temp_buffer(src); + bufferInfo src_info; + populate_buffer_info(src, src_info); + private_handle_t* src_hnd = new private_handle_t(-1, 0, 0, 0, src_info.format, + src_info.width, src_info.height); + if (NULL == src_hnd) { + LOGE("%s: src_hnd is null", __FUNCTION__); + if (needTempDestination) { + free_temp_image(dst_hnd); + } + delete_handle(dst_hnd); + return COPYBIT_FAILURE; + } + if (needTempSource) { + // Create a temp buffer and set that as the destination. + if (COPYBIT_SUCCESS == get_temp_buffer(src_info, mem_info)) { + src_hnd->fd = mem_info.fd; + src_hnd->size = mem_info.size; + src_hnd->flags = private_handle_t::PRIV_FLAGS_USES_ASHMEM; + src_hnd->base = mem_info.base; + src_hnd->offset = 0; + src_hnd->gpuaddr = 0; + src_image.handle = src_hnd; + + // Copy the source. + copy_image((private_handle_t *)src->handle, &src_image, CONVERT_TO_C2D_FORMAT); + + // Flush the cache + if (ioctl(src_hnd->fd, ASHMEM_CACHE_FLUSH_RANGE, NULL)) { + LOGE("%s: ASHMEM_CACHE_FLUSH_RANGE failed (error=%s)", + __FUNCTION__, strerror(errno)); + if (needTempDestination) { + free_temp_image(dst_hnd); + } + free_temp_image(src_hnd); + delete_handle(dst_hnd); + delete_handle(src_hnd); + return COPYBIT_FAILURE; + } + } + } + + status = set_image(ctx->g12_device_fd, ctx->src[src_surface_index], &src_image, &cformat, + &src_mapped, (eC2DFlags)flags); if(status) { - LOGE("%s: set_src_image error", __func__); + LOGE("%s: set_src_image error", __FUNCTION__); + if (needTempDestination) { + free_temp_image(dst_hnd); + } + if (needTempSource) { + free_temp_image(src_hnd); + } + delete_handle(dst_hnd); + delete_handle(src_hnd); return COPYBIT_FAILURE; } @@ -941,8 +1216,16 @@ static int stretch_copybit_internal( ctx->blitState.config_mask &= ~C2D_ALPHA_BLEND_NONE; if(!(ctx->blitState.global_alpha)) { // src alpha is zero - unset_image(ctx->g12_device_fd, ctx->src[src_surface_index], src, src_mapped); - unset_image(ctx->g12_device_fd, ctx->dst[dst_surface_index], dst, trg_mapped); + unset_image(ctx->g12_device_fd, ctx->src[src_surface_index], &src_image, src_mapped); + unset_image(ctx->g12_device_fd, ctx->dst[dst_surface_index], &dst_image, trg_mapped); + if (needTempDestination) { + free_temp_image(dst_hnd); + } + if (needTempSource) { + free_temp_image(src_hnd); + } + delete_handle(dst_hnd); + delete_handle(src_hnd); return status; } } else { @@ -976,9 +1259,20 @@ static int stretch_copybit_internal( LOGE("%s: LINK_c2dFinish ERROR", __FUNCTION__); } - - unset_image(ctx->g12_device_fd, ctx->src[src_surface_index], src, src_mapped); - unset_image(ctx->g12_device_fd, ctx->dst[dst_surface_index], dst, trg_mapped); + unset_image(ctx->g12_device_fd, ctx->src[src_surface_index], &src_image, src_mapped); + unset_image(ctx->g12_device_fd, ctx->dst[dst_surface_index], &dst_image, trg_mapped); + if (needTempDestination) { + // copy the temp. destination without the alignment to the actual destination. + copy_image(dst_hnd, dst, CONVERT_TO_ANDROID_FORMAT); + // Free the temp memory. + free_temp_image(dst_hnd); + } + if (needTempSource) { + // Free the temp memory. + free_temp_image(src_hnd); + } + delete_handle(dst_hnd); + delete_handle(src_hnd); ctx->isPremultipliedAlpha = false; ctx->fb_width = 0; ctx->fb_height = 0; diff --git a/libcopybit/software_converter.cpp b/libcopybit/software_converter.cpp index 73c2c88..10e9db2 100644 --- a/libcopybit/software_converter.cpp +++ b/libcopybit/software_converter.cpp @@ -32,7 +32,6 @@ #include #include #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; +} \ No newline at end of file diff --git a/libcopybit/software_converter.h b/libcopybit/software_converter.h index 345c7c0..8f98a93 100644 --- a/libcopybit/software_converter.h +++ b/libcopybit/software_converter.h @@ -30,9 +30,36 @@ #include +#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); From 0afa0e42a61dd3d0a6c7e558f51ff5e37727e550 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Sun, 11 Dec 2011 15:27:51 -0800 Subject: [PATCH 30/33] libhwcomposer: Use the HWC private flags from libQcomUI. Qcom specific private flags have been moved to libQcomUI. Use these flags flags in the hwcomposer. Change-Id: I9898dd11a7fff72678fa1f744454fcf310507a63 --- libhwcomposer/Android.mk | 1 + libhwcomposer/hwcomposer.cpp | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk index 099ee2f..72ef88f 100755 --- a/libhwcomposer/Android.mk +++ b/libhwcomposer/Android.mk @@ -18,6 +18,7 @@ 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 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index 298dc3c..9d327ea 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -38,6 +38,7 @@ #include #include #include +#include /*****************************************************************************/ #define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) @@ -59,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, From 75e2a92af424ec26a1ea5f563c6dcc493bb8da0a Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Wed, 14 Dec 2011 16:54:25 +0530 Subject: [PATCH 31/33] hwc: Initialize padding for copybit Change-Id: I053431caa114fdc9a09584933b10b4d27d34ec74 CRs-fixed: 324785 --- libhwcomposer/hwcomposer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index 9d327ea..0c092c1 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -996,6 +996,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; From 8287f5bbcb8eb1deb03b4effff57a6f029c6dd80 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Mon, 12 Dec 2011 18:03:29 -0800 Subject: [PATCH 32/33] libhwcomposer: Validate the previous overlay and bypass handles. Validate the previous overlay and bypass handles before unlocking the buffers. The reason for doing this, is that in certain use cases, after the previous handles are stored, the buffer gets destroyed and the handle is now invalid. The HWC however doesn't know that the handle is invalid and tries to unlock the handle, resulting in a failure. CRs-fixed: 323614 Change-Id: I0f0c8506e7e22f9fc01eb28af0270f9c4587c787 --- libgralloc/gralloc_priv.h | 1 + libhwcomposer/hwcomposer.cpp | 41 ++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 6f109a1..00039c4 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -285,6 +285,7 @@ struct private_handle_t { PRIV_FLAGS_DO_NOT_FLUSH = 0x00000040, PRIV_FLAGS_SW_LOCK = 0x00000080, PRIV_FLAGS_NONCONTIGUOUS_MEM = 0x00000100, + PRIV_FLAGS_HWC_LOCK = 0x00000200, // Set by HWC when storing the handle }; // file-descriptors diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index 0c092c1..e713807 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -237,10 +237,19 @@ void unlockPreviousBypassBuffers(hwc_context_t* ctx) { for(int i = 0; i < MAX_BYPASS_LAYERS; i++) { if (ctx->previousBypassHandle[i]) { private_handle_t *hnd = (private_handle_t*) ctx->previousBypassHandle[i]; - if (GENLOCK_FAILURE == genlock_unlock_buffer(ctx->previousBypassHandle[i])) { - LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); - } else { - ctx->previousBypassHandle[i] = NULL; + // 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; + } } } } @@ -330,11 +339,18 @@ static int prepareOverlay(hwc_context_t *ctx, hwc_layer_t *layer, const bool wai void unlockPreviousOverlayBuffer(hwc_context_t* ctx) { if (ctx->previousOverlayHandle) { - // Unlock any previously locked buffers - if (GENLOCK_NO_ERROR == genlock_unlock_buffer(ctx->previousOverlayHandle)) { - ctx->previousOverlayHandle = NULL; - } else { - LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); + // 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__); + } + } } } } @@ -491,6 +507,7 @@ 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__); @@ -644,9 +661,10 @@ void storeLockedBypassHandle(hwc_layer_list_t* list, hwc_context_t* ctx) { // 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) + if (ctx->bypassBufferLockState[index] == BYPASS_BUFFER_LOCKED) { ctx->previousBypassHandle[index] = (native_handle_t*)list->hwLayers[index].handle; - else + hnd->flags |= private_handle_t::PRIV_FLAGS_HWC_LOCK; + } else ctx->previousBypassHandle[index] = NULL; } } @@ -1093,6 +1111,7 @@ static int drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer) // 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; From d120c0dfac62a02ed1e8b1d76a6c1ea88ef825da Mon Sep 17 00:00:00 2001 From: Mathew Karimpanal Date: Sat, 10 Dec 2011 22:13:05 -0800 Subject: [PATCH 33/33] libhwcomposer: Mark layers below skip-layers for GPU composition If module composition type is MDP or C2D and we have a skipped layer (usually layers without backing buffers, layers with "invalid" orientations or debug layers), mark every HWC layer below this layer for GPU composition. This logic is needed because ICS SF composes a bunch of z-ordered HWC_FRAMEBUFFER (GPU) layers first and then the remaining bunch of z-ordered HWC_OVERLAY layers last which breaks the overall z-ordered layer rendering requirement. This logic also holds valid for 2-layer bypass in ICS. Change-Id: I5082affac8affd6b19d78be827d149901945a163 --- libhwcomposer/hwcomposer.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index e713807..517ae82 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -863,6 +863,28 @@ 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)) {