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