Gralloc/Camera3: Support new HAL_PIXEL_FORMAT_YCbCr_420_888 format

Enable flexible YUV format buffers from the camera.

 - Add gralloc alloc support for YCbCr_420_888, mapped to NV21
 - Add gralloc lock_ycbcr method
 - Add new format to list supported by camera HAL
 - Fix minor compilation warnings

Bug: 8734880
Change-Id: I68a8cc126985c7d5ae100a87b31c60ee59074cd3
diff --git a/system/gralloc/gralloc.cpp b/system/gralloc/gralloc.cpp
index 311146f..ed5d05f 100644
--- a/system/gralloc/gralloc.cpp
+++ b/system/gralloc/gralloc.cpp
@@ -154,6 +154,8 @@
     bool hw_cam_read = usage & GRALLOC_USAGE_HW_CAMERA_READ;
     bool hw_vid_enc_read = usage & GRALLOC_USAGE_HW_VIDEO_ENCODER;
 
+    // Keep around original requested format for later validation
+    int frameworkFormat = format;
     // Pick the right concrete pixel format given the endpoints as encoded in
     // the usage bits.  Every end-point pair needs explicit listing here.
     if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
@@ -178,8 +180,17 @@
                     w, h, usage);
             return -EINVAL;
         }
+    } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        // Flexible framework-accessible YUV format; map to NV21 for now
+        if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
+            format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+        }
+        if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+            ALOGE("gralloc_alloc: Requested YCbCr_420_888, but no known "
+                    "specific format for this usage: %d x %d, usage %x",
+                    w, h, usage);
+        }
     }
-
     bool yuv_format = false;
 
     int ashmem_size = 0;
@@ -297,7 +308,8 @@
     }
 
     cb_handle_t *cb = new cb_handle_t(fd, ashmem_size, usage,
-                                      w, h, format, glFormat, glType);
+                                      w, h, frameworkFormat, format,
+                                      glFormat, glType);
 
     if (ashmem_size > 0) {
         //
@@ -350,7 +362,11 @@
     pthread_mutex_unlock(&grdev->lock);
 
     *pHandle = cb;
-    *pStride = stride;
+    if (frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        *pStride = 0;
+    } else {
+        *pStride = stride;
+    }
     return 0;
 }
 
@@ -580,7 +596,7 @@
             ERR("gralloc_unregister_buffer(%p): unmap failed", cb);
             return -EINVAL;
         }
-        cb->ashmemBase = NULL;
+        cb->ashmemBase = 0;
         cb->mappedPid = 0;
     }
 
@@ -605,6 +621,12 @@
         return -EINVAL;
     }
 
+    // validate format
+    if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        ALOGE("gralloc_lock can't be used with YCbCr_420_888 format");
+        return -EINVAL;
+    }
+
     // Validate usage,
     //   1. cannot be locked for hw access
     //   2. lock for either sw read or write.
@@ -759,6 +781,109 @@
     return 0;
 }
 
+static int gralloc_lock_ycbcr(gralloc_module_t const* module,
+                        buffer_handle_t handle, int usage,
+                        int l, int t, int w, int h,
+                        android_ycbcr *ycbcr)
+{
+    // Not supporting fallback module for YCbCr
+    if (sFallback != NULL) {
+        return -EINVAL;
+    }
+
+    if (!ycbcr) {
+        ALOGE("gralloc_lock_ycbcr got NULL ycbcr struct");
+        return -EINVAL;
+    }
+
+    private_module_t *gr = (private_module_t *)module;
+    cb_handle_t *cb = (cb_handle_t *)handle;
+    if (!gr || !cb_handle_t::validate(cb)) {
+        ALOGE("gralloc_lock_ycbcr bad handle\n");
+        return -EINVAL;
+    }
+
+    if (cb->frameworkFormat != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        ALOGE("gralloc_lock_ycbcr can only be used with "
+                "HAL_PIXEL_FORMAT_YCbCr_420_888, got %x instead",
+                cb->frameworkFormat);
+        return -EINVAL;
+    }
+
+    // Validate usage
+    // For now, only allow camera write, software read.
+    bool sw_read = (0 != (usage & GRALLOC_USAGE_SW_READ_MASK));
+    bool hw_cam_write = (usage & GRALLOC_USAGE_HW_CAMERA_WRITE);
+    bool sw_read_allowed = (0 != (cb->usage & GRALLOC_USAGE_SW_READ_MASK));
+
+    if ( (!hw_cam_write && !sw_read) ||
+            (sw_read && !sw_read_allowed) ) {
+        ALOGE("gralloc_lock_ycbcr usage mismatch usage:0x%x cb->usage:0x%x\n",
+                usage, cb->usage);
+        return -EINVAL;
+    }
+
+    // Make sure memory is mapped, get address
+    if (cb->ashmemBasePid != getpid() || !cb->ashmemBase) {
+        return -EACCES;
+    }
+
+    uint8_t *cpu_addr = NULL;
+
+    if (cb->canBePosted()) {
+        cpu_addr = (uint8_t *)(cb->ashmemBase + sizeof(int));
+    }
+    else {
+        cpu_addr = (uint8_t *)(cb->ashmemBase);
+    }
+
+    // Calculate offsets to underlying YUV data
+    size_t yStride;
+    size_t cStride;
+    size_t yOffset;
+    size_t uOffset;
+    size_t vOffset;
+    size_t cStep;
+    switch (cb->format) {
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            yStride = cb->width;
+            cStride = cb->width;
+            yOffset = 0;
+            vOffset = yStride * cb->height;
+            uOffset = vOffset + 1;
+            cStep = 2;
+            break;
+        default:
+            ALOGE("gralloc_lock_ycbcr unexpected internal format %x",
+                    cb->format);
+            return -EINVAL;
+    }
+
+    ycbcr->y = cpu_addr + yOffset;
+    ycbcr->cb = cpu_addr + uOffset;
+    ycbcr->cr = cpu_addr + vOffset;
+    ycbcr->ystride = yStride;
+    ycbcr->cstride = cStride;
+    ycbcr->chroma_step = cStep;
+
+    // Zero out reserved fields
+    memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
+
+    //
+    // Keep locked region if locked for s/w write access.
+    //
+    cb->lockedLeft = l;
+    cb->lockedTop = t;
+    cb->lockedWidth = w;
+    cb->lockedHeight = h;
+
+    DD("gralloc_lock_ycbcr success. usage: %x, ycbcr.y: %p, .cb: %p, .cr: %p, "
+            ".ystride: %d , .cstride: %d, .chroma_step: %d", usage,
+            ycbcr->y, ycbcr->cb, ycbcr->cr, ycbcr->ystride, ycbcr->cstride,
+            ycbcr->chroma_step);
+
+    return 0;
+}
 
 static int gralloc_device_open(const hw_module_t* module,
                                const char* name,
@@ -881,8 +1006,8 @@
     base: {
         common: {
             tag: HARDWARE_MODULE_TAG,
-            version_major: 1,
-            version_minor: 0,
+            module_api_version: GRALLOC_MODULE_API_VERSION_0_2,
+            hal_api_version: 0,
             id: GRALLOC_HARDWARE_MODULE_ID,
             name: "Graphics Memory Allocator Module",
             author: "The Android Open Source Project",
@@ -894,7 +1019,9 @@
         unregisterBuffer: gralloc_unregister_buffer,
         lock: gralloc_lock,
         unlock: gralloc_unlock,
-        perform: NULL
+        perform: NULL,
+        lock_ycbcr: gralloc_lock_ycbcr,
+        reserved_proc: {0, }
     }
 };