display: Add display metadata in buffer handle

Allocate extra space for metadata in buffer handles
Provide api to map this space in client process and set the metadata

Change-Id: I8bca8448670d4aa88d439320faf402dae30458f8
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index f79841c..7b2c1d8 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -27,6 +27,7 @@
 #include "gpu.h"
 #include "memalloc.h"
 #include "alloc_controller.h"
+#include <qdMetaData.h>
 
 using namespace gralloc;
 
@@ -137,37 +138,52 @@
     data.pHandle = (unsigned int) pHandle;
     err = mAllocCtrl->allocate(data, usage);
 
-    if (usage & GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED) {
-        flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED;
-    }
+    if (!err) {
+        /* allocate memory for enhancement data */
+        alloc_data eData;
+        eData.fd = -1;
+        eData.base = 0;
+        eData.offset = 0;
+        eData.size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+        eData.pHandle = data.pHandle;
+        eData.align = getpagesize();
+        int eDataUsage = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP;
+        int eDataErr = mAllocCtrl->allocate(eData, eDataUsage);
+        ALOGE_IF(eDataErr, "gralloc failed for eDataErr=%s",
+                                          strerror(-eDataErr));
 
-    if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) {
-        flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY;
-        //The EXTERNAL_BLOCK flag is always an add-on
-        if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK) {
-            flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK;
-        }if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_CC) {
-            flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_CC;
+        if (usage & GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED) {
+            flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED;
         }
-    }
 
-    if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER ) {
-        flags |= private_handle_t::PRIV_FLAGS_VIDEO_ENCODER;
-    }
+        if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) {
+            flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY;
+            //The EXTERNAL_BLOCK flag is always an add-on
+            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK) {
+                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK;
+            }
+            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_CC) {
+                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_CC;
+            }
+        }
 
-    if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
-        flags |= private_handle_t::PRIV_FLAGS_CAMERA_WRITE;
-    }
+        if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER ) {
+            flags |= private_handle_t::PRIV_FLAGS_VIDEO_ENCODER;
+        }
 
-    if (usage & GRALLOC_USAGE_HW_CAMERA_READ) {
-        flags |= private_handle_t::PRIV_FLAGS_CAMERA_READ;
-    }
+        if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
+            flags |= private_handle_t::PRIV_FLAGS_CAMERA_WRITE;
+        }
 
-    if (err == 0) {
+        if (usage & GRALLOC_USAGE_HW_CAMERA_READ) {
+            flags |= private_handle_t::PRIV_FLAGS_CAMERA_READ;
+        }
+
         flags |= data.allocType;
-        private_handle_t* hnd = new private_handle_t(data.fd, size, flags,
-                                                     bufferType, format, width,
-                                                     height);
+        int eBaseAddr = int(eData.base) + eData.offset;
+        private_handle_t *hnd = new private_handle_t(data.fd, size, flags,
+                bufferType, format, width, height, eData.fd, eData.offset,
+                eBaseAddr);
 
         hnd->offset = data.offset;
         hnd->base = int(data.base) + data.offset;
@@ -175,6 +191,7 @@
     }
 
     ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));
+
     return err;
 }
 
@@ -261,6 +278,13 @@
                                         hnd->offset, hnd->fd);
         if(err)
             return err;
+        // free the metadata space
+        unsigned long size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+        err = memalloc->free_buffer((void*)hnd->base_metadata,
+                                    (size_t) size, hnd->offset_metadata,
+                                    hnd->fd_metadata);
+        if (err)
+            return err;
     }
 
     // Release the genlock
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index 4f6445d..6ccc7e0 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -30,6 +30,9 @@
 
 #include <cutils/log.h>
 
+#define ROUND_UP_PAGESIZE(x) ( (((unsigned long)(x)) + PAGE_SIZE-1)  & \
+                               (~(PAGE_SIZE-1)) )
+
 enum {
     /* gralloc usage bits indicating the type
      * of allocation that should be used */
@@ -167,6 +170,7 @@
         int     fd;
         // genlock handle to be dup'd by the binder
         int     genlockHandle;
+        int     fd_metadata;          // fd for the meta-data
         // ints
         int     magic;
         int     flags;
@@ -174,6 +178,7 @@
         int     offset;
         int     bufferType;
         int     base;
+        int     offset_metadata;
         // The gpu address mapped into the mmu.
         // If using ashmem, set to 0, they don't care
         int     gpuaddr;
@@ -183,19 +188,21 @@
         int     height;
         // local fd of the genlock device.
         int     genlockPrivFd;
+        int     base_metadata;
 
 #ifdef __cplusplus
-        static const int sNumInts = 12;
-        static const int sNumFds = 2;
+        static const int sNumInts = 14;
+        static const int sNumFds = 3;
         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), gpuaddr(0),
-            pid(0), format(format),
-            width(width), height(height), genlockPrivFd(-1)
+                         int format,int width, int height, int eFd = -1,
+                         int eOffset = 0, int eBase = 0) :
+            fd(fd), genlockHandle(-1), fd_metadata(eFd), magic(sMagic),
+            flags(flags), size(size), offset(0), bufferType(bufferType),
+            base(0), offset_metadata(eOffset), gpuaddr(0), pid(getpid()),
+            format(format), width(width), height(height), genlockPrivFd(-1),
+            base_metadata(eBase)
         {
             version = sizeof(native_handle);
             numInts = sNumInts;
diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp
index 3088ecc..176a84e 100644
--- a/libgralloc/mapper.cpp
+++ b/libgralloc/mapper.cpp
@@ -42,6 +42,7 @@
 #include "gr.h"
 #include "alloc_controller.h"
 #include "memalloc.h"
+#include <qdMetaData.h>
 
 using namespace gralloc;
 /*****************************************************************************/
@@ -68,22 +69,27 @@
         IMemAlloc* memalloc = getAllocator(hnd->flags) ;
         int err = memalloc->map_buffer(&mappedAddress, size,
                                        hnd->offset, hnd->fd);
-        if(err) {
+        if(err || mappedAddress == MAP_FAILED) {
             ALOGE("Could not mmap handle %p, fd=%d (%s)",
                   handle, hnd->fd, strerror(errno));
             hnd->base = 0;
             return -errno;
         }
 
-        if (mappedAddress == MAP_FAILED) {
-            ALOGE("Could not mmap handle %p, fd=%d (%s)",
-                  handle, hnd->fd, strerror(errno));
-            hnd->base = 0;
-            return -errno;
-        }
         hnd->base = intptr_t(mappedAddress) + hnd->offset;
         //LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
         //        hnd->fd, hnd->offset, hnd->size, mappedAddress);
+        mappedAddress = MAP_FAILED;
+        size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+        err = memalloc->map_buffer(&mappedAddress, size,
+                                       hnd->offset_metadata, hnd->fd_metadata);
+        if(err || mappedAddress == MAP_FAILED) {
+            ALOGE("Could not mmap handle %p, fd=%d (%s)",
+                  handle, hnd->fd_metadata, strerror(errno));
+            hnd->base_metadata = 0;
+            return -errno;
+        }
+        hnd->base_metadata = intptr_t(mappedAddress) + hnd->offset_metadata;
     }
     *vaddr = (void*)hnd->base;
     return 0;
@@ -98,10 +104,17 @@
         void* base = (void*)hnd->base;
         size_t size = hnd->size;
         IMemAlloc* memalloc = getAllocator(hnd->flags) ;
-        if(memalloc != NULL)
+        if(memalloc != NULL) {
             err = memalloc->unmap_buffer(base, size, hnd->offset);
-        if (err) {
-            ALOGE("Could not unmap memory at address %p", base);
+            if (err) {
+                ALOGE("Could not unmap memory at address %p", base);
+            }
+            base = (void*)hnd->base_metadata;
+            size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+            err = memalloc->unmap_buffer(base, size, hnd->offset_metadata);
+            if (err) {
+                ALOGE("Could not unmap memory at address %p", base);
+            }
         }
     }
     hnd->base = 0;
@@ -277,6 +290,12 @@
                                      hnd->size, hnd->offset, hnd->fd);
         ALOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x, flags = 0x%x) err=%s\n",
                  hnd, hnd->offset, hnd->size, hnd->flags, strerror(errno));
+        unsigned long size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+        err = memalloc->clean_buffer((void*)hnd->base_metadata, size,
+                hnd->offset_metadata, hnd->fd_metadata);
+        ALOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%lu, "
+                "flags = 0x%x) err=%s\n", hnd, hnd->offset_metadata, size,
+                hnd->flags, strerror(errno));
         hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
     }
 
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 4200be9..3bca539 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -19,6 +19,7 @@
 #include "hwc_mdpcomp.h"
 #include <sys/ioctl.h>
 #include "external.h"
+#include "qdMetaData.h"
 
 namespace qhwc {
 
@@ -96,11 +97,15 @@
 
 void MDPComp::setVidInfo(hwc_layer_1_t *layer, ovutils::eMdpFlags &mdpFlags) {
     private_handle_t *hnd = (private_handle_t *)layer->handle;
+    MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
 
     if(isSecureBuffer(hnd)) {
         ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
         sSecuredVid = true;
     }
+    if((metadata->operation & PP_PARAM_INTERLACED) && metadata->interlaced) {
+        ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_DEINTERLACE);
+    }
 }
 
 /*
diff --git a/libhwcomposer/hwc_video.cpp b/libhwcomposer/hwc_video.cpp
index 48cb165..1784593 100644
--- a/libhwcomposer/hwc_video.cpp
+++ b/libhwcomposer/hwc_video.cpp
@@ -19,6 +19,7 @@
 #include <overlay.h>
 #include "hwc_video.h"
 #include "hwc_utils.h"
+#include "qdMetaData.h"
 
 namespace qhwc {
 
@@ -106,6 +107,11 @@
                 ovutils::OV_MDP_BLEND_FG_PREMULT);
     }
 
+    MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+    if ((metadata->operation & PP_PARAM_INTERLACED) && metadata->interlaced) {
+        ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_DEINTERLACE);
+    }
+
     ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
     if (ctx->listStats[dpy].numAppLayers == 1) {
         isFgFlag = ovutils::IS_FG_SET;
diff --git a/libqdutils/Android.mk b/libqdutils/Android.mk
index ed8bed0..ecae273 100644
--- a/libqdutils/Android.mk
+++ b/libqdutils/Android.mk
@@ -12,3 +12,19 @@
                                  idle_invalidator.cpp
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_COPY_HEADERS_TO           := qcom/display
+LOCAL_COPY_HEADERS              := qdMetaData.h
+LOCAL_MODULE_PATH               := $(TARGET_OUT_SHARED_LIBRARIES)
+LOCAL_SHARED_LIBRARIES          := liblog libcutils
+LOCAL_C_INCLUDES                := $(common_includes)
+LOCAL_ADDITIONAL_DEPENDENCIES   := $(common_deps)
+LOCAL_SRC_FILES                 := qdMetaData.cpp
+LOCAL_CFLAGS                    := $(common_flags)
+LOCAL_CFLAGS                    += -DLOG_TAG=\"DisplayMetaData\"
+LOCAL_MODULE_TAGS               := optional
+LOCAL_MODULE                    := libqdMetaData
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/libqdutils/qdMetaData.cpp b/libqdutils/qdMetaData.cpp
new file mode 100644
index 0000000..a53ba07
--- /dev/null
+++ b/libqdutils/qdMetaData.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. 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 The Linux Foundation 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 <string.h>
+#include <sys/mman.h>
+#include <cutils/log.h>
+#include <gralloc_priv.h>
+#include "qdMetaData.h"
+
+int setMetaData(private_handle_t *handle, DispParamType paramType,
+                                                    void *param) {
+    if (!handle) {
+        ALOGE("%s: Private handle is null!", __func__);
+        return -1;
+    }
+    if (handle->fd_metadata == -1) {
+        ALOGE("%s: Bad fd for extra data!", __func__);
+        return -1;
+    }
+    unsigned long size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+    void *base = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED,
+        handle->fd_metadata, 0);
+    if (!base) {
+        ALOGE("%s: mmap() failed: Base addr is NULL!", __func__);
+        return -1;
+    }
+    MetaData_t *data = reinterpret_cast <MetaData_t *>(base);
+    data->operation |= paramType;
+    switch (paramType) {
+        case PP_PARAM_HSIC:
+            memcpy((void *)&data->hsicData, param, sizeof(HSICData_t));
+            break;
+        case PP_PARAM_SHARPNESS:
+            data->sharpness = *((int32_t *)param);
+            break;
+        case PP_PARAM_VID_INTFC:
+            data->video_interface = *((int32_t *)param);
+            break;
+        case PP_PARAM_INTERLACED:
+            data->interlaced = *((int32_t *)param);
+            break;
+        default:
+            ALOGE("Unknown paramType %d", paramType);
+            break;
+    }
+    if(munmap(base, size))
+        ALOGE("%s: failed to unmap ptr 0x%x, err %d", __func__, (int)base,
+                                                                        errno);
+    return 0;
+}
diff --git a/libqdutils/qdMetaData.h b/libqdutils/qdMetaData.h
new file mode 100644
index 0000000..e60daed
--- /dev/null
+++ b/libqdutils/qdMetaData.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. 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 The Linux Foundation 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 _QDMETADATA_H
+#define _QDMETADATA_H
+
+
+typedef struct {
+    int32_t hue;
+    float   saturation;
+    int32_t intensity;
+    float   contrast;
+} HSICData_t;
+
+typedef struct {
+    int32_t operation;
+    int32_t interlaced;
+    HSICData_t hsicData;
+    int32_t sharpness;
+    int32_t video_interface;
+} MetaData_t;
+
+typedef enum {
+    PP_PARAM_HSIC       = 0x0001,
+    PP_PARAM_SHARPNESS  = 0x0002,
+    PP_PARAM_INTERLACED = 0x0004,
+    PP_PARAM_VID_INTFC  = 0x0008
+} DispParamType;
+
+int setMetaData(private_handle_t *handle, DispParamType paramType, void *param);
+
+#endif /* _QDMETADATA_H */
+