gralloc: Add automatic format selection

Have gralloc_alloc be able to select the appropriate pixel format
given the endpoints, triggered by new
GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO format.

Currently supports camera->screen, and camera->video encoder.

Bug: 6243944
Change-Id: Ib1bf8da8d9184ac99e7f50aad09212c146c32809
diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/gralloc_cb.h b/tools/emulator/opengl/system/OpenglSystemCommon/gralloc_cb.h
index e879409..a3fb8dd 100644
--- a/tools/emulator/opengl/system/OpenglSystemCommon/gralloc_cb.h
+++ b/tools/emulator/opengl/system/OpenglSystemCommon/gralloc_cb.h
@@ -25,22 +25,35 @@
 #define CB_HANDLE_NUM_INTS(nfds) (int)((sizeof(cb_handle_t) - (nfds)*sizeof(int)) / sizeof(int))
 
 //
+// Emulator-specific gralloc formats
+//
+enum {
+    // Request that gralloc select the proper format given the usage
+    // flags. Pass this as the format to gralloc_alloc, and then the concrete
+    // format can be found in cb_handle_t.format. It is invalid for
+    // cb_handle_t.format to be AUTO; it must be a concrete format in either the
+    // standard HAL_PIXEL_FORMAT enum or other values in this enum.
+    GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO = 0x100
+};
+
+//
 // Our buffer handle structure
 //
 struct cb_handle_t : public native_handle {
 
     cb_handle_t(int p_fd, int p_ashmemSize, int p_usage,
-                int p_width, int p_height,
+                int p_width, int p_height, int p_format,
                 int p_glFormat, int p_glType) :
         fd(p_fd),
         magic(BUFFER_HANDLE_MAGIC),
         usage(p_usage),
         width(p_width),
         height(p_height),
+        format(p_format),
         glFormat(p_glFormat),
         glType(p_glType),
         ashmemSize(p_ashmemSize),
-        ashmemBase(NULL),
+        ashmemBase(0),
         ashmemBasePid(0),
         mappedPid(0),
         lockedLeft(0),
@@ -88,6 +101,7 @@
     int usage;              // usage bits the buffer was created with
     int width;              // buffer width
     int height;             // buffer height
+    int format;             // real internal pixel format format
     int glFormat;           // OpenGL format enum used for host h/w color buffer
     int glType;             // OpenGL type enum used when uploading to host
     int ashmemSize;         // ashmem region size for the buffer (0 unless is HW_FB buffer or
diff --git a/tools/emulator/opengl/system/egl/egl.cpp b/tools/emulator/opengl/system/egl/egl.cpp
index b1be38d..da89c4d 100644
--- a/tools/emulator/opengl/system/egl/egl.cpp
+++ b/tools/emulator/opengl/system/egl/egl.cpp
@@ -1146,7 +1146,9 @@
     if (native_buffer->common.version != sizeof(android_native_buffer_t))
         setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
 
-    switch (native_buffer->format) {
+    cb_handle_t *cb = (cb_handle_t *)(native_buffer->handle);
+
+    switch (cb->format) {
         case HAL_PIXEL_FORMAT_RGBA_8888:
         case HAL_PIXEL_FORMAT_RGBX_8888:
         case HAL_PIXEL_FORMAT_RGB_888:
diff --git a/tools/emulator/opengl/system/gralloc/gralloc.cpp b/tools/emulator/opengl/system/gralloc/gralloc.cpp
index 3953f9c..dd5e515 100644
--- a/tools/emulator/opengl/system/gralloc/gralloc.cpp
+++ b/tools/emulator/opengl/system/gralloc/gralloc.cpp
@@ -133,8 +133,11 @@
     D("gralloc_alloc w=%d h=%d usage=0x%x\n", w, h, usage);
 
     gralloc_device_t *grdev = (gralloc_device_t *)dev;
-    if (!grdev || !pHandle || !pStride)
+    if (!grdev || !pHandle || !pStride) {
+        ALOGE("gralloc_alloc: Bad inputs (grdev: %p, pHandle: %p, pStride: %p",
+                grdev, pHandle, pStride);
         return -EINVAL;
+    }
 
     //
     // Validate usage: buffer cannot be written both by s/w and h/w access.
@@ -142,9 +145,37 @@
     bool sw_write = (0 != (usage & GRALLOC_USAGE_SW_WRITE_MASK));
     bool hw_write = (usage & GRALLOC_USAGE_HW_RENDER);
     if (hw_write && sw_write) {
+        ALOGE("gralloc_alloc: Mismatched usage flags: %d x %d, usage %x",
+                w, h, usage);
         return -EINVAL;
     }
     bool sw_read = (0 != (usage & GRALLOC_USAGE_SW_READ_MASK));
+    bool hw_cam_write = usage & GRALLOC_USAGE_HW_CAMERA_WRITE;
+    bool hw_cam_read = usage & GRALLOC_USAGE_HW_CAMERA_READ;
+    bool hw_vid_enc_read = usage & GRALLOC_USAGE_HW_VIDEO_ENCODER;
+
+    // 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 == GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO) {
+        // Camera as producer
+        if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
+            if (usage & GRALLOC_USAGE_HW_TEXTURE) {
+                // Camera-to-display is RGBA
+                format = HAL_PIXEL_FORMAT_RGBA_8888;
+            } else if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) {
+                // Camera-to-encoder is NV21
+                format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+            }
+        }
+
+        if (format == GRALLOC_EMULATOR_PIXEL_FORMAT_AUTO) {
+            ALOGE("gralloc_alloc: Requested auto format selection, "
+                    "but no known format for this usage: %d x %d, usage %x",
+                    w, h, usage);
+            return -EINVAL;
+        }
+    }
+
     bool yuv_format = false;
 
     int ashmem_size = 0;
@@ -186,8 +217,8 @@
         case HAL_PIXEL_FORMAT_RAW_SENSOR:
             bpp = 2;
             align = 16*bpp;
-            if (! (sw_read && sw_write) ) {
-                // Raw sensor data cannot be used by HW
+            if (! ((sw_read && hw_cam_write) || (sw_write && hw_cam_read) ) ) {
+                // Raw sensor data only goes to/from camera to CPU
                 return -EINVAL;
             }
             // Not expecting to actually create any GL surfaces for this
@@ -196,8 +227,8 @@
             break;
         case HAL_PIXEL_FORMAT_BLOB:
             bpp = 1;
-            if (! (sw_read && sw_write) ) {
-                // Blob data cannot be used by HW
+            if (! (sw_read && hw_cam_write) ) {
+                // Blob data cannot be used by HW other than camera emulator
                 return -EINVAL;
             }
             // Not expecting to actually create any GL surfaces for this
@@ -210,6 +241,7 @@
             // Not expecting to actually create any GL surfaces for this
             break;
         default:
+            ALOGE("gralloc_alloc: Unknown format %d", format);
             return -EINVAL;
     }
 
@@ -218,9 +250,9 @@
         ashmem_size += sizeof(uint32_t);
     }
 
-    if (sw_read || sw_write) {
+    if (sw_read || sw_write || hw_cam_write || hw_vid_enc_read) {
         // keep space for image on guest memory if SW access is needed
-
+        // or if the camera is doing writing
         if (yuv_format) {
             // For NV21
             ashmem_size += w * h * 3 / 2;
@@ -232,8 +264,8 @@
         }
     }
 
-    D("gralloc_alloc ashmem_size=%d, stride=%d, tid %d\n", ashmem_size, stride,
-            gettid());
+    D("gralloc_alloc format=%d, ashmem_size=%d, stride=%d, tid %d\n", format,
+            ashmem_size, stride, gettid());
 
     //
     // Allocate space in ashmem if needed
@@ -252,7 +284,7 @@
     }
 
     cb_handle_t *cb = new cb_handle_t(fd, ashmem_size, usage,
-                                      w, h, glFormat, glType);
+                                      w, h, format, glFormat, glType);
 
     if (ashmem_size > 0) {
         //
@@ -271,8 +303,11 @@
 
     //
     // Allocate ColorBuffer handle on the host (only if h/w access is allowed)
+    // Only do this for some h/w usages, not all.
     //
-    if (usage & GRALLOC_USAGE_HW_MASK) {
+    if (usage & (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER |
+                    GRALLOC_USAGE_HW_2D | GRALLOC_USAGE_HW_COMPOSER |
+                    GRALLOC_USAGE_HW_FB) ) {
         DEFINE_HOST_CONNECTION;
         if (hostCon && rcEnc) {
             cb->hostHandle = rcEnc->rcCreateColorBuffer(rcEnc, w, h, glFormat);
@@ -565,14 +600,17 @@
     bool sw_write = (0 != (usage & GRALLOC_USAGE_SW_WRITE_MASK));
     bool hw_read = (usage & GRALLOC_USAGE_HW_TEXTURE);
     bool hw_write = (usage & GRALLOC_USAGE_HW_RENDER);
+    bool hw_vid_enc_read = (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER);
+    bool hw_cam_write = (usage & GRALLOC_USAGE_HW_CAMERA_WRITE);
     bool sw_read_allowed = (0 != (cb->usage & GRALLOC_USAGE_SW_READ_MASK));
     bool sw_write_allowed = (0 != (cb->usage & GRALLOC_USAGE_SW_WRITE_MASK));
 
     if ( (hw_read || hw_write) ||
-         (!sw_read && !sw_write) ||
+         (!sw_read && !sw_write && !hw_cam_write && !hw_vid_enc_read) ||
          (sw_read && !sw_read_allowed) ||
          (sw_write && !sw_write_allowed) ) {
-        ALOGE("gralloc_lock usage mismatch usage=0x%x cb->usage=0x%x\n", usage, cb->usage);
+        ALOGE("gralloc_lock usage mismatch usage=0x%x cb->usage=0x%x\n", usage,
+                cb->usage);
         return -EINVAL;
     }
 
@@ -582,7 +620,7 @@
     //
     // make sure ashmem area is mapped if needed
     //
-    if (cb->canBePosted() || sw_read || sw_write) {
+    if (cb->canBePosted() || sw_read || sw_write || hw_cam_write || hw_vid_enc_read) {
         if (cb->ashmemBasePid != getpid() || !cb->ashmemBase) {
             return -EACCES;
         }
@@ -619,11 +657,11 @@
     //
     // is virtual address required ?
     //
-    if (sw_read || sw_write) {
+    if (sw_read || sw_write || hw_cam_write || hw_vid_enc_read) {
         *vaddr = cpu_addr;
     }
 
-    if (sw_write) {
+    if (sw_write || hw_cam_write) {
         //
         // Keep locked region if locked for s/w write access.
         //
@@ -633,6 +671,9 @@
         cb->lockedHeight = h;
     }
 
+    DD("gralloc_lock success. vaddr: %p, *vaddr: %p, usage: %x, cpu_addr: %p",
+            vaddr, vaddr ? *vaddr : 0, usage, cpu_addr);
+
     return 0;
 }