Initial version of the gralloc module for SwiftShader

Change-Id: Ia092831a101e1916ee5a00c5ce9b607ecb6a9fef
Reviewed-on: https://swiftshader-review.googlesource.com/2945
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Greg Hartman <ghartman@google.com>
diff --git a/src/gralloc/Android.mk b/src/gralloc/Android.mk
new file mode 100644
index 0000000..67f0137
--- /dev/null
+++ b/src/gralloc/Android.mk
@@ -0,0 +1,47 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# 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.
+
+
+LOCAL_PATH := $(call my-dir)
+
+# HAL module implemenation stored in
+# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_INSTALLED_MODULE_STEM := gralloc.gce_x86.so
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libutils \
+    libcutils
+
+LOCAL_STATIC_LIBRARIES := \
+    libgceframebufferconfig \
+    libgcemetadata \
+    libyuv_static
+
+LOCAL_SRC_FILES := 	\
+	gralloc.cpp 	\
+	framebuffer.cpp \
+	mapper.cpp
+
+LOCAL_MODULE := gralloc_swiftshader.gce_x86
+LOCAL_CFLAGS:= -DLOG_TAG=\"gralloc_gce_x86\" -Wno-missing-field-initializers
+
+LOCAL_C_INCLUDES := \
+    device/google/gce/include \
+    external/libyuv/files/include
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/src/gralloc/framebuffer.cpp b/src/gralloc/framebuffer.cpp
new file mode 100644
index 0000000..e72d614
--- /dev/null
+++ b/src/gralloc/framebuffer.cpp
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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 <sys/mman.h>
+
+#include <dlfcn.h>
+
+#include <cutils/ashmem.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <sys/system_properties.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <cutils/sockets.h>
+#include <private/android_filesystem_config.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/fb.h>
+#endif
+
+#include "gralloc_priv.h"
+#include "gr.h"
+
+#include <GceFrameBufferConfig.h>
+#include "remoter_framework_pkt.h"
+
+/*****************************************************************************/
+
+// numbers of buffers for page flipping
+#define NUM_BUFFERS 2
+
+enum {
+    PAGE_FLIP = 0x00000001,
+    LOCKED = 0x00000002
+};
+
+struct fb_context_t {
+    framebuffer_device_t  device;
+};
+
+/*****************************************************************************/
+
+static int fb_setSwapInterval(struct framebuffer_device_t* dev,
+            int interval)
+{
+    fb_context_t* ctx = (fb_context_t*)dev;
+    if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval)
+        return -EINVAL;
+    // FIXME: implement fb_setSwapInterval
+    return 0;
+}
+
+static int fb_setUpdateRect(struct framebuffer_device_t* dev,
+        int l, int t, int w, int h)
+{
+    if (((w|h) <= 0) || ((l|t)<0))
+        return -EINVAL;
+        
+    fb_context_t* ctx = (fb_context_t*)dev;
+    private_module_t* m = reinterpret_cast<private_module_t*>(
+            dev->common.module);
+    if (m->remoter_socket != -1) {
+        struct remoter_request_packet pkt;
+        remoter_request_packet_init(&pkt, REMOTER_OP_FB_UPDATE_RECT, 0);
+        pkt.params.fb_update_rect_params.left = l;
+        pkt.params.fb_update_rect_params.top = t;
+        pkt.params.fb_update_rect_params.width = w;
+        pkt.params.fb_update_rect_params.height = h;
+        if (write(m->remoter_socket, &pkt, sizeof(pkt)) < 0) {
+            ALOGE("Remoter socket write failed (%s)", strerror(errno));
+        }
+    } else
+        ALOGW("Remoter socket not connected!");
+    return 0;
+}
+
+static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
+{
+    if (private_handle_t::validate(buffer) < 0)
+        return -EINVAL;
+
+    fb_context_t* ctx = (fb_context_t*)dev;
+
+    private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);
+    private_module_t* m = reinterpret_cast<private_module_t*>(
+            dev->common.module);
+
+    if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
+        const size_t offset = uintptr_t(hnd->base) - uintptr_t(m->framebuffer->base);
+        m->info.yoffset = offset / m->finfo.line_length;
+        if (m->remoter_socket != -1) {
+            struct remoter_request_packet pkt;
+            remoter_request_packet_init(&pkt, REMOTER_OP_FB_POST, 0);
+            pkt.params.fb_post_params.y_offset  = m->info.yoffset;
+            if (write(m->remoter_socket, &pkt, sizeof(pkt)) < 0) {
+                ALOGE("Remoter socket write failed (%s)", strerror(errno));
+            }
+        } else
+            ALOGW("Remoter socket not connected!");
+        m->currentBuffer = buffer;
+    } else {
+        // If we can't do the page_flip, just copy the buffer to the front 
+        // FIXME: use copybit HAL instead of memcpy
+        
+        void* fb_vaddr;
+        void* buffer_vaddr;
+        
+        m->base.lock(&m->base, m->framebuffer, 
+                GRALLOC_USAGE_SW_WRITE_RARELY, 
+                0, 0, m->info.xres, m->info.yres,
+                &fb_vaddr);
+
+        m->base.lock(&m->base, buffer, 
+                GRALLOC_USAGE_SW_READ_RARELY, 
+                0, 0, m->info.xres, m->info.yres,
+                &buffer_vaddr);
+
+        memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
+        
+        m->base.unlock(&m->base, buffer); 
+        m->base.unlock(&m->base, m->framebuffer); 
+    }
+    
+    return 0;
+}
+
+int wait_for_remoter() {
+    char prop_value[PROP_VALUE_MAX];
+    const char* prop_name = "ro.remoter_ready";
+    int retries = (60 * 5);
+
+    ALOGI("wait_for_remoter():");
+    while(retries--) {
+        if (property_get(prop_name, prop_value, NULL) <= 0) {
+            sleep(1);
+            continue;
+        } else {
+            ALOGI("wait_for_remoter(): Remoter ready");
+            break;
+        }
+    }
+    if (!retries) {
+        ALOGE("Timed out waiting for remoter");
+        return -1;
+    }
+    return 0;
+}
+
+/*****************************************************************************/
+int mapUserspaceFrameBufferLocked(struct private_module_t* module)
+{
+    if (module->framebuffer) {
+        return 0;
+    }
+
+    if (wait_for_remoter()) {
+        ALOGE("Remoter not available");
+        return -ENOENT;
+    }
+
+    int fd;
+    if ((fd = open(GceFrameBufferConfig::kFrameBufferPath, O_RDWR, 0)) < 0) {
+      ALOGE("Failed to open '%s' (%s)",
+            GceFrameBufferConfig::kFrameBufferPath, strerror(errno));
+      return -errno;
+    }
+
+    struct fb_fix_screeninfo finfo;
+    struct fb_var_screeninfo info;
+    memset(&info, 0, sizeof(info));
+
+    const GceFrameBufferConfig* config = GceFrameBufferConfig::getInstance();
+
+    info.xres = config->x_res();
+    info.yres = config->y_res();
+    info.bits_per_pixel = config->bits_per_pixel();
+
+    info.red.offset = GceFrameBufferConfig::kRedShift;
+    info.red.length = GceFrameBufferConfig::kRedBits;
+    info.green.offset = GceFrameBufferConfig::kGreenShift;
+    info.green.length = GceFrameBufferConfig::kGreenBits;
+    info.blue.offset = GceFrameBufferConfig::kBlueShift;
+    info.blue.length = GceFrameBufferConfig::kBlueBits;
+    info.xres_virtual = info.xres;
+    info.yres_virtual = config->y_res_virtual();
+    info.xoffset = 0;
+    info.yoffset = 0;
+    info.pixclock = 0;
+    info.vmode = FB_VMODE_NONINTERLACED;
+    info.width  = ((info.xres * 25.4f) / config->dpi() + 0.5f);
+    info.height = ((info.yres * 25.4f) / config->dpi() + 0.5f);
+
+    memset(&finfo, 0, sizeof(finfo));
+    strcpy(finfo.id, "Userspace FB");
+    finfo.type = FB_TYPE_PACKED_PIXELS;
+    finfo.line_length = info.xres * (info.bits_per_pixel / 8);
+    finfo.accel = FB_ACCEL_NONE;
+
+    module->flags = PAGE_FLIP;
+    module->info = info;
+    module->finfo = finfo;
+    module->xdpi = (info.xres * 25.4f) / info.width;
+    module->ydpi = (info.yres * 25.4f) / info.height;
+    module->fps = (60 * 1000) / 1000.0f;
+
+    /*
+     * map the framebuffer
+     */
+
+    size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
+    module->framebuffer = new private_handle_t(
+        dup(fd), fbSize,
+        config->hal_format(), config->x_res(), config->y_res(), 0);
+    module->numBuffers = info.yres_virtual / info.yres;
+    module->bufferMask = 0;
+
+    void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+    if (vaddr == MAP_FAILED) {
+        ALOGE("Error mapping the framebuffer (%s)", strerror(errno));
+        return -errno;
+    }
+    module->framebuffer->base = vaddr;
+    memset(vaddr, 0, fbSize);
+
+    // Connect to the remoter so we can notify it of posted buffers and updated
+    // regions.
+    if ((module->remoter_socket = socket_local_client(
+        "remoter", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM)) < 0) {
+        ALOGE("Error connecting to remoter (%s)", strerror(errno));
+        return -errno;
+    }
+    
+    return 0;
+}
+
+static int mapUserspaceFrameBuffer(struct private_module_t* module)
+{
+    pthread_mutex_lock(&module->lock);
+    int err = mapUserspaceFrameBufferLocked(module);
+    pthread_mutex_unlock(&module->lock);
+    return err;
+}
+
+
+/*****************************************************************************/
+
+static int fb_close(struct hw_device_t *dev)
+{
+    fb_context_t* ctx = (fb_context_t*)dev;
+    if (ctx) {
+        free(ctx);
+    }
+    return 0;
+}
+
+int fb_device_open(hw_module_t const* module, const char* name,
+        hw_device_t** device)
+{
+    int status = -EINVAL;
+    if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
+        char prop_value[PATH_MAX];
+        /* initialize our state here */
+        fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
+        memset(dev, 0, sizeof(*dev));
+
+        /* initialize the procs */
+        dev->device.common.tag = HARDWARE_DEVICE_TAG;
+        dev->device.common.version = 0;
+        dev->device.common.module = const_cast<hw_module_t*>(module);
+        dev->device.common.close = fb_close;
+        dev->device.setSwapInterval = fb_setSwapInterval;
+        dev->device.post            = fb_post;
+        dev->device.setUpdateRect   = fb_setUpdateRect;
+
+        private_module_t* m = (private_module_t*)module;
+
+        status = mapUserspaceFrameBuffer(m);
+
+        if (status >= 0) {
+            int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
+            int format =
+                GceFrameBufferConfig::getInstance()->hal_format();
+            const_cast<uint32_t&>(dev->device.flags) = 0;
+            const_cast<uint32_t&>(dev->device.width) = m->info.xres;
+            const_cast<uint32_t&>(dev->device.height) = m->info.yres;
+            const_cast<int&>(dev->device.stride) = stride;
+            const_cast<int&>(dev->device.format) = format;
+            const_cast<float&>(dev->device.xdpi) = m->xdpi;
+            const_cast<float&>(dev->device.ydpi) = m->ydpi;
+            const_cast<float&>(dev->device.fps) = m->fps;
+            const_cast<int&>(dev->device.minSwapInterval) = 1;
+            const_cast<int&>(dev->device.maxSwapInterval) = 1;
+            *device = &dev->device.common;
+        }
+    }
+    return status;
+}
diff --git a/src/gralloc/gr.h b/src/gralloc/gr.h
new file mode 100644
index 0000000..7e9b5ff
--- /dev/null
+++ b/src/gralloc/gr.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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 GR_H_
+#define GR_H_
+
+#include <stdint.h>
+#include <limits.h>
+#include <sys/cdefs.h>
+#include <hardware/gralloc.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include <cutils/native_handle.h>
+
+/*****************************************************************************/
+
+struct private_module_t;
+struct private_handle_t;
+
+inline size_t roundUpToPageSize(size_t x) {
+    return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
+}
+
+int mapUserspaceFrameBufferLocked(struct private_module_t* module);
+int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd);
+int mapBuffer(gralloc_module_t const* module, private_handle_t* hnd);
+
+/*****************************************************************************/
+
+class Locker {
+    pthread_mutex_t mutex;
+public:
+    class Autolock {
+        Locker& locker;
+    public:
+        inline Autolock(Locker& locker) : locker(locker) {  locker.lock(); }
+        inline ~Autolock() { locker.unlock(); }
+    };
+    inline Locker()        { pthread_mutex_init(&mutex, 0); }
+    inline ~Locker()       { pthread_mutex_destroy(&mutex); }
+    inline void lock()     { pthread_mutex_lock(&mutex); }
+    inline void unlock()   { pthread_mutex_unlock(&mutex); }
+};
+
+#endif /* GR_H_ */
diff --git a/src/gralloc/gralloc.cpp b/src/gralloc/gralloc.cpp
new file mode 100644
index 0000000..fd65822
--- /dev/null
+++ b/src/gralloc/gralloc.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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 <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <cutils/ashmem.h>
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <utils/String8.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+
+#include <api_level_fixes.h>
+
+#include "GceFrameBufferConfig.h"
+#include "gralloc_priv.h"
+#include "gr.h"
+
+/*****************************************************************************/
+
+struct gralloc_context_t {
+  alloc_device_t  device;
+  /* our private data here */
+};
+
+static int gralloc_alloc_buffer(
+    alloc_device_t* dev, int format, int w, int h,
+    buffer_handle_t* pHandle, int* pStrideInPixels);
+
+/*****************************************************************************/
+
+static int gralloc_device_open(
+    const hw_module_t* module, const char* name, hw_device_t** device);
+
+
+/*****************************************************************************/
+
+static struct hw_module_methods_t gralloc_module_methods = {
+  .open = gralloc_device_open
+};
+
+struct private_module_t HAL_MODULE_INFO_SYM = {
+  .base = {
+    .common = {
+      .tag = HARDWARE_MODULE_TAG,
+      .version_major = 1,
+      .version_minor = 0,
+#ifdef GCE_CONVERTING_GRALLOC
+      .id = "converting_gralloc",
+#else
+      .id = GRALLOC_HARDWARE_MODULE_ID,
+#endif
+      .name = "GCE X86 Graphics Memory Allocator Module",
+      .author = "The Android Open Source Project",
+      .methods = &gralloc_module_methods
+    },
+    .registerBuffer = gralloc_register_buffer,
+    .unregisterBuffer = gralloc_unregister_buffer,
+#ifdef GCE_CONVERTING_GRALLOC
+    .lock = gralloc_converting_lock,
+    .unlock = gralloc_converting_unlock,
+#else
+    .lock = gralloc_lock,
+    .unlock = gralloc_unlock,
+#endif
+    },
+  .framebuffer = 0,
+  .remoter_socket = -1,
+  .flags = 0,
+  .numBuffers = 0,
+  .bufferMask = 0,
+  .lock = PTHREAD_MUTEX_INITIALIZER,
+  .currentBuffer = 0,
+};
+
+/*****************************************************************************/
+
+static int gralloc_alloc_framebuffer_locked(
+    alloc_device_t* dev,
+    buffer_handle_t* pHandle, int* pStrideInPixels) {
+  static const GceFrameBufferConfig* config =
+      GceFrameBufferConfig::getInstance();
+
+  private_module_t* m = reinterpret_cast<private_module_t*>(
+      dev->common.module);
+  // allocate the framebuffer
+  if (m->framebuffer == NULL) {
+    // The framebuffer is mapped once and forever.
+    int err = mapUserspaceFrameBufferLocked(m);
+    if (err < 0) {
+      ALOGE("Failed to map framebuffer (%d)", errno);
+      return err;
+    }
+  }
+
+  const uint32_t bufferMask = m->bufferMask;
+  const uint32_t numBuffers = m->numBuffers;
+  const size_t bufferSize = m->finfo.line_length * m->info.yres;
+  if (numBuffers == 1) {
+    // If we have only one buffer, we never use page-flipping. Instead,
+    // we return a regular buffer which will be memcpy'ed to the main
+    // screen when post is called.
+    return gralloc_alloc_buffer(
+        dev, config->hal_format(), config->x_res(), config->y_res(),
+        pHandle, pStrideInPixels);
+  }
+
+  if (bufferMask >= ((1LU<<numBuffers)-1)) {
+    // We ran out of buffers.
+    return -ENOMEM;
+  }
+
+  // create a "fake" handles for it
+  intptr_t vaddr = intptr_t(m->framebuffer->base);
+  private_handle_t* hnd = new private_handle_t(
+      dup(m->framebuffer->fd), bufferSize,
+      config->hal_format(), config->x_res(), config->y_res(),
+      private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
+
+  // find a free slot
+  for (uint32_t i=0 ; i<numBuffers ; i++) {
+    if ((bufferMask & (1LU << i)) == 0) {
+      m->bufferMask |= (1LU << i);
+      break;
+    }
+    vaddr += bufferSize;
+  }
+
+  hnd->base = reinterpret_cast<void*>(vaddr);
+  hnd->frame_offset = vaddr - intptr_t(m->framebuffer->base);
+  *pHandle = hnd;
+  *pStrideInPixels = config->line_length() / (config->bits_per_pixel() / 8);
+
+  return 0;
+}
+
+static int gralloc_alloc_framebuffer(
+    alloc_device_t* dev,
+    buffer_handle_t* pHandle, int* pStrideInPixels) {
+  private_module_t* m = reinterpret_cast<private_module_t*>(
+      dev->common.module);
+  pthread_mutex_lock(&m->lock);
+  int err = gralloc_alloc_framebuffer_locked(dev, pHandle, pStrideInPixels);
+  pthread_mutex_unlock(&m->lock);
+  return err;
+}
+
+static int gralloc_alloc_buffer(
+    alloc_device_t* dev, int format, int w, int h,
+    buffer_handle_t* pHandle, int* pStrideInPixels) {
+  int err = 0;
+  int fd = -1;
+  static int sequence = 0;
+
+  int bytes_per_pixel = formatToBytesPerPixel(format);
+  int bytes_per_line = GceFrameBufferConfig::align(bytes_per_pixel * w);
+  int size = GceFrameBufferConfig::align(sizeof(gralloc_buffer_control_t));
+  int primary_offset = size;
+  size = roundUpToPageSize(size + bytes_per_line * h);
+  size += PAGE_SIZE;
+  int secondary_offset = 0;
+  if (bytes_per_pixel != 4) {
+    secondary_offset = size;
+    size += roundUpToPageSize(GceFrameBufferConfig::align(4 * w) * h);
+    size += PAGE_SIZE;
+  }
+
+  fd = ashmem_create_region(
+      android::String8::format(
+          "gralloc-%d.%d", getpid(), sequence++).string(),
+      size);
+  if (fd < 0) {
+    ALOGE("couldn't create ashmem (%s)", strerror(-errno));
+    err = -errno;
+  }
+
+  if (err == 0) {
+    private_handle_t* hnd = new private_handle_t(fd, size, format, w, h, 0);
+    hnd->primary_offset = primary_offset;
+    hnd->secondary_offset = secondary_offset;
+    gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>(
+        dev->common.module);
+    err = mapBuffer(module, hnd);
+    if (err == 0) {
+      reinterpret_cast<gralloc_buffer_control_t*>(hnd->base)->last_locked =
+          gralloc_buffer_control_t::PRIMARY;
+      *pHandle = hnd;
+      *pStrideInPixels = bytes_per_line / bytes_per_pixel;
+    }
+  }
+
+  ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));
+
+  return err;
+}
+
+/*****************************************************************************/
+
+static int gralloc_alloc(
+    alloc_device_t* dev, int w, int h, int format, int usage,
+    buffer_handle_t* pHandle, int* pStrideInPixels) {
+  if (!pHandle || !pStrideInPixels)
+    return -EINVAL;
+
+  int err;
+  if (usage & GRALLOC_USAGE_HW_FB) {
+    err = gralloc_alloc_framebuffer(dev, pHandle, pStrideInPixels);
+  } else {
+    err = gralloc_alloc_buffer(dev, format, w, h, pHandle, pStrideInPixels);
+  }
+
+  if (err < 0) {
+    return err;
+  }
+  return 0;
+}
+
+static int gralloc_free(alloc_device_t* dev,
+        buffer_handle_t handle) {
+  if (private_handle_t::validate(handle) < 0)
+    return -EINVAL;
+
+  private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle);
+  if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
+    // free this buffer
+    private_module_t* m = reinterpret_cast<private_module_t*>(
+        dev->common.module);
+    const size_t bufferSize = m->finfo.line_length * m->info.yres;
+    int index = (uintptr_t(hnd->base) - uintptr_t(m->framebuffer->base)) / bufferSize;
+    m->bufferMask &= ~(1 << index);
+  } else {
+    gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>(
+        dev->common.module);
+    terminateBuffer(module, const_cast<private_handle_t*>(hnd));
+  }
+
+  close(hnd->fd);
+  delete hnd;
+  return 0;
+}
+
+/*****************************************************************************/
+
+static int gralloc_close(struct hw_device_t *dev) {
+  gralloc_context_t* ctx = reinterpret_cast<gralloc_context_t*>(dev);
+  if (ctx) {
+    /* TODO: keep a list of all buffer_handle_t created, and free them
+     * all here.
+     */
+    free(ctx);
+  }
+  return 0;
+}
+
+int gralloc_device_open(const hw_module_t* module, const char* name,
+        hw_device_t** device) {
+  int status = -EINVAL;
+  if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
+    gralloc_context_t *dev;
+    dev = (gralloc_context_t*)malloc(sizeof(*dev));
+
+    /* initialize our state here */
+    memset(dev, 0, sizeof(*dev));
+
+    /* initialize the procs */
+    dev->device.common.tag = HARDWARE_DEVICE_TAG;
+    dev->device.common.version = 0;
+    dev->device.common.module = const_cast<hw_module_t*>(module);
+    dev->device.common.close = gralloc_close;
+
+    dev->device.alloc   = gralloc_alloc;
+    dev->device.free    = gralloc_free;
+
+    *device = &dev->device.common;
+    status = 0;
+  } else {
+    status = fb_device_open(module, name, device);
+  }
+  return status;
+}
diff --git a/src/gralloc/mapper.cpp b/src/gralloc/mapper.cpp
new file mode 100644
index 0000000..4e74947
--- /dev/null
+++ b/src/gralloc/mapper.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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 <limits.h>
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+
+#include <utils/ashmem.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+
+#include <libyuv/convert_argb.h>
+#include <libyuv/convert_from.h>
+
+#include "GceFrameBufferConfig.h"
+
+#include "gralloc_priv.h"
+
+
+/* desktop Linux needs a little help with gettid() */
+#if defined(ARCH_X86) && !defined(HAVE_ANDROID_OS)
+#define __KERNEL__
+# include <linux/unistd.h>
+pid_t gettid() { return syscall(__NR_gettid);}
+#undef __KERNEL__
+#endif
+
+static const char* buffer_name(
+    private_handle_t* hnd, char output[ASHMEM_NAME_LEN]) {
+  output[0] = '\0';
+  if (!hnd) {
+    ALOGE("Attempted to log gralloc name hnd=NULL");
+    return output;
+  }
+  if (hnd->fd == -1) {
+    ALOGE("Attempted to log gralloc name hnd=%p with fd == -1", hnd);
+    return output;
+  }
+  int rval = ioctl(hnd->fd, ASHMEM_GET_NAME, output);
+  if (rval == -1) {
+    ALOGE("ASHMEM_GET_NAME failed, hnd=%p fd=%d (%s)", hnd, hnd->fd,
+        strerror(errno));
+  }
+  return output;
+}
+
+/*****************************************************************************/
+
+static int gralloc_map(gralloc_module_t const* /*module*/,
+        buffer_handle_t handle,
+        void** vaddr) {
+  char name_buf[ASHMEM_NAME_LEN];
+  private_handle_t* hnd = (private_handle_t*)handle;
+  if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
+    size_t size = hnd->total_size;
+    void* mappedAddress = mmap(
+        0, size, PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);
+    if (mappedAddress == MAP_FAILED) {
+      ALOGE("Could not mmap %s", strerror(errno));
+      return -errno;
+    }
+    // Set up the guard pages. The last page is always a guard
+    uintptr_t base = uintptr_t(mappedAddress);
+    uintptr_t addr = base + hnd->total_size - PAGE_SIZE;
+    if (mprotect((void*)addr, PAGE_SIZE, PROT_NONE) == -1) {
+      ALOGE("mprotect base=%p, pg=%p failed (%s)",
+            (void*)base, (void*)addr, strerror(errno));
+    }
+    // If we have a secondary buffer, then the page before it is also
+    // a guard page.
+    if (hnd->secondary_offset) {
+      addr = base + hnd->secondary_offset - PAGE_SIZE;
+      if (mprotect((void*)addr, PAGE_SIZE, PROT_NONE) == -1) {
+        ALOGE("mprotect base=%p, sec_pg=%p failed (%s)",
+              (void*)base, (void*)addr, strerror(errno));
+      }
+    }
+    hnd->base = reinterpret_cast<void*>(
+        uintptr_t(mappedAddress) + hnd->frame_offset);
+    ALOGI("Mapped %s hnd=%p fd=%d base=%p", buffer_name(hnd, name_buf), hnd,
+          hnd->fd, hnd->base);
+    ALOGI("... %s format=%d width=%d height=%d", name_buf, hnd->format,
+          hnd->x_res, hnd->y_res);
+    //ALOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
+    //        hnd->fd, hnd->offset, hnd->size, mappedAddress);
+  } else {
+    ALOGI("Mapped framebuffer hnd=%p base=%p", hnd, hnd->base);
+  }
+  *vaddr = (void*)hnd->base;
+  return 0;
+}
+
+static int gralloc_unmap(gralloc_module_t const* /*module*/,
+        buffer_handle_t handle) {
+  char name_buf[ASHMEM_NAME_LEN];
+
+  private_handle_t* hnd = (private_handle_t*)handle;
+  if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
+    ALOGI("Unmapped %s hnd=%p fd=%d base=%p", buffer_name(hnd, name_buf), hnd,
+          hnd->fd, hnd->base);
+    if (munmap(hnd->base, hnd->total_size) < 0) {
+      ALOGE("Could not unmap %s", strerror(errno));
+    }
+  }
+  hnd->base = 0;
+  return 0;
+}
+
+/*****************************************************************************/
+
+int gralloc_register_buffer(gralloc_module_t const* module,
+        buffer_handle_t handle) {
+  char name_buf[ASHMEM_NAME_LEN];
+
+  if (private_handle_t::validate(handle) < 0)
+    return -EINVAL;
+
+  // *** WARNING WARNING WARNING ***
+  //
+  // If a buffer handle is passed from the process that allocated it to a
+  // different process, and then back to the allocator process, we will
+  // create a second mapping of the buffer. If the process reads and writes
+  // through both mappings, normal memory ordering guarantees may be
+  // violated, depending on the processor cache implementation*.
+  //
+  // If you are deriving a new gralloc implementation from this code, don't
+  // do this. A "real" gralloc should provide a single reference-counted
+  // mapping for each buffer in a process.
+  //
+  // In the current system, there is one case that needs a buffer to be
+  // registered in the same process that allocated it. The SurfaceFlinger
+  // process acts as the IGraphicBufferAlloc Binder provider, so all gralloc
+  // allocations happen in its process. After returning the buffer handle to
+  // the IGraphicBufferAlloc client, SurfaceFlinger free's its handle to the
+  // buffer (unmapping it from the SurfaceFlinger process). If
+  // SurfaceFlinger later acts as the producer end of the buffer queue the
+  // buffer belongs to, it will get a new handle to the buffer in response
+  // to IGraphicBufferProducer::requestBuffer(). Like any buffer handle
+  // received through Binder, the SurfaceFlinger process will register it.
+  // Since it already freed its original handle, it will only end up with
+  // one mapping to the buffer and there will be no problem.
+  //
+  // Currently SurfaceFlinger only acts as a buffer producer for a remote
+  // consumer when taking screenshots and when using virtual displays.
+  //
+  // Eventually, each application should be allowed to make its own gralloc
+  // allocations, solving the problem. Also, this ashmem-based gralloc
+  // should go away, replaced with a real ion-based gralloc.
+  //
+  // * Specifically, associative virtually-indexed caches are likely to have
+  //   problems. Most modern L1 caches fit that description.
+
+  private_handle_t* hnd = (private_handle_t*)handle;
+   ALOGI("Registered %s hnd=%p fd=%d", buffer_name(hnd, name_buf), hnd,
+          hnd->fd);
+   ALOGD_IF(hnd->allocating_pid == getpid(),
+           "Registering a buffer in the process that created it. "
+           "This may cause memory ordering problems.");
+
+  void *vaddr;
+  return gralloc_map(module, handle, &vaddr);
+}
+
+int gralloc_unregister_buffer(gralloc_module_t const* module,
+        buffer_handle_t handle) {
+  char name_buf[ASHMEM_NAME_LEN];
+
+  if (private_handle_t::validate(handle) < 0)
+    return -EINVAL;
+
+  private_handle_t* hnd = (private_handle_t*)handle;
+  ALOGI("Unregistered %s hnd=%p fd=%d", buffer_name(hnd, name_buf), hnd,
+        hnd->fd);
+  if (hnd->base)
+    gralloc_unmap(module, handle);
+
+  return 0;
+}
+
+int mapBuffer(gralloc_module_t const* module,
+        private_handle_t* hnd) {
+  void* vaddr;
+  return gralloc_map(module, hnd, &vaddr);
+}
+
+int terminateBuffer(gralloc_module_t const* module,
+        private_handle_t* hnd) {
+  if (hnd->base) {
+    // this buffer was mapped, unmap it now
+    gralloc_unmap(module, hnd);
+  }
+
+  return 0;
+}
+
+#ifdef GCE_CONVERTING_GRALLOC
+int gralloc_converting_lock(
+    gralloc_module_t const* module, buffer_handle_t handle, int usage,
+    int l, int t, int w, int h, void** vaddr) {
+  char name_buf[ASHMEM_NAME_LEN];
+
+  if (private_handle_t::validate(handle) < 0) {
+    return -EINVAL;
+  }
+
+  private_handle_t* hnd = (private_handle_t*)handle;
+  buffer_name(hnd, name_buf);
+  gralloc_buffer_control_t* control = NULL;
+  if (hnd->primary_offset) {
+    control = reinterpret_cast<gralloc_buffer_control_t*>(hnd->base);
+  }
+  unsigned char* primary_buffer = reinterpret_cast<unsigned char*>(
+      uintptr_t(hnd->base) + hnd->primary_offset);
+  unsigned char* secondary_buffer = hnd->secondary_offset ?
+      reinterpret_cast<unsigned char*>(
+          uintptr_t(hnd->base) + hnd->secondary_offset) : primary_buffer;
+
+  if (hnd->format == HAL_PIXEL_FORMAT_RGB_565) {
+    if (control &&
+        (control->last_locked == gralloc_buffer_control_t::PRIMARY)) {
+      ALOGI("Converting RGB16 to RGB32 %s", name_buf);
+      libyuv::RGB565ToARGB(
+          primary_buffer,  GceFrameBufferConfig::align(hnd->x_res * 2),
+          secondary_buffer, GceFrameBufferConfig::align(hnd->x_res * 4),
+          hnd->x_res, hnd->y_res);
+      control->last_locked = gralloc_buffer_control_t::SECONDARY;
+    } else {
+      ALOGE("Can't convert: RGB16, but no control structure %s", name_buf);
+    }
+    *vaddr = secondary_buffer;
+  } else {
+    *vaddr = primary_buffer;
+  }
+  ALOGI("Locking buffer %s hnd=%p secondary=%d at=%p",
+        name_buf, hnd, (control ? control->last_locked : 0), *vaddr);
+  return 0;
+}
+
+int gralloc_converting_unlock(gralloc_module_t const* module,
+        buffer_handle_t handle) {
+  if (private_handle_t::validate(handle) < 0)
+    return -EINVAL;
+  return 0;
+}
+#else
+int gralloc_lock(gralloc_module_t const* /*module*/,
+        buffer_handle_t handle, int /*usage*/,
+        int /*l*/, int /*t*/, int /*w*/, int /*h*/,
+        void** vaddr) {
+  char name_buf[ASHMEM_NAME_LEN];
+  // this is called when a buffer is being locked for software
+  // access. in thin implementation we have nothing to do since
+  // not synchronization with the h/w is needed.
+  // typically this is used to wait for the h/w to finish with
+  // this buffer if relevant. the data cache may need to be
+  // flushed or invalidated depending on the usage bits and the
+  // hardware.
+
+  if (private_handle_t::validate(handle) < 0)
+    return -EINVAL;
+
+  private_handle_t* hnd = (private_handle_t*)handle;
+  buffer_name(hnd, name_buf);
+  gralloc_buffer_control_t* control = NULL;
+  if (hnd->primary_offset) {
+    control = reinterpret_cast<gralloc_buffer_control_t*>(hnd->base);
+  }
+  unsigned char* primary_buffer = reinterpret_cast<unsigned char*>(
+      uintptr_t(hnd->base) + hnd->primary_offset);
+  unsigned char* secondary_buffer = hnd->secondary_offset ?
+      reinterpret_cast<unsigned char*>(
+          uintptr_t(hnd->base) + hnd->secondary_offset) : primary_buffer;
+  if (control &&
+      (control->last_locked == gralloc_buffer_control_t::SECONDARY)) {
+    ALOGI("Converting RGB32 to RGB16 %s", name_buf);
+    libyuv::ARGBToRGB565(
+        secondary_buffer, GceFrameBufferConfig::align(hnd->x_res * 4),
+        primary_buffer, GceFrameBufferConfig::align(hnd->x_res * 2),
+        hnd->x_res, hnd->y_res);
+    control->last_locked = gralloc_buffer_control_t::PRIMARY;
+  }
+  *vaddr = primary_buffer;
+  return 0;
+}
+
+int gralloc_unlock(gralloc_module_t const* /*module*/,
+        buffer_handle_t handle) {
+  // we're done with a software buffer. nothing to do in this
+  // implementation. typically this is used to flush the data cache.
+
+  if (private_handle_t::validate(handle) < 0)
+    return -EINVAL;
+  return 0;
+}
+
+#endif