add android-x86 files
Bring in gralloc_drm files verbatim from the kitkat-x86 branch of Android-x86:
http://git.android-x86.org/
BUG=chromium:358029
TEST=none
Change-Id: Ic18bc41b91ce3d5841a26876b7a55c09f4b13240
Reviewed-on: https://chromium-review.googlesource.com/201365
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
Reviewed-by: Robert Kroeger <rjkroege@chromium.org>
Commit-Queue: Frank Henigman <fjhenigman@chromium.org>
Tested-by: Frank Henigman <fjhenigman@chromium.org>
diff --git a/src/drm_gralloc/gralloc.c b/src/drm_gralloc/gralloc.c
new file mode 100644
index 0000000..92866ca
--- /dev/null
+++ b/src/drm_gralloc/gralloc.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#define LOG_TAG "GRALLOC-MOD"
+
+#include <cutils/log.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "gralloc_drm.h"
+#include "gralloc_drm_priv.h"
+
+/*
+ * Initialize the DRM device object, optionally with KMS.
+ */
+static int drm_init(struct drm_module_t *dmod, int kms)
+{
+ int err = 0;
+
+ pthread_mutex_lock(&dmod->mutex);
+ if (!dmod->drm) {
+ dmod->drm = gralloc_drm_create();
+ if (!dmod->drm)
+ err = -EINVAL;
+ }
+ if (!err && kms)
+ err = gralloc_drm_init_kms(dmod->drm);
+ pthread_mutex_unlock(&dmod->mutex);
+
+ return err;
+}
+
+static int drm_mod_perform(const struct gralloc_module_t *mod, int op, ...)
+{
+ struct drm_module_t *dmod = (struct drm_module_t *) mod;
+ va_list args;
+ int err;
+
+ err = drm_init(dmod, 0);
+ if (err)
+ return err;
+
+ va_start(args, op);
+ switch (op) {
+ case GRALLOC_MODULE_PERFORM_GET_DRM_FD:
+ {
+ int *fd = va_arg(args, int *);
+ *fd = gralloc_drm_get_fd(dmod->drm);
+ err = 0;
+ }
+ break;
+ /* should we remove this and next ops, and make it transparent? */
+ case GRALLOC_MODULE_PERFORM_GET_DRM_MAGIC:
+ {
+ int32_t *magic = va_arg(args, int32_t *);
+ err = gralloc_drm_get_magic(dmod->drm, magic);
+ }
+ break;
+ case GRALLOC_MODULE_PERFORM_AUTH_DRM_MAGIC:
+ {
+ int32_t magic = va_arg(args, int32_t);
+ err = gralloc_drm_auth_magic(dmod->drm, magic);
+ }
+ break;
+ case GRALLOC_MODULE_PERFORM_ENTER_VT:
+ {
+ err = gralloc_drm_set_master(dmod->drm);
+ }
+ break;
+ case GRALLOC_MODULE_PERFORM_LEAVE_VT:
+ {
+ gralloc_drm_drop_master(dmod->drm);
+ err = 0;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ va_end(args);
+
+ return err;
+}
+
+static int drm_mod_register_buffer(const gralloc_module_t *mod,
+ buffer_handle_t handle)
+{
+ struct drm_module_t *dmod = (struct drm_module_t *) mod;
+ int err;
+
+ err = drm_init(dmod, 0);
+ if (err)
+ return err;
+
+ return gralloc_drm_handle_register(handle, dmod->drm);
+}
+
+static int drm_mod_unregister_buffer(const gralloc_module_t *mod,
+ buffer_handle_t handle)
+{
+ return gralloc_drm_handle_unregister(handle);
+}
+
+static int drm_mod_lock(const gralloc_module_t *mod, buffer_handle_t handle,
+ int usage, int x, int y, int w, int h, void **ptr)
+{
+ struct gralloc_drm_bo_t *bo;
+ int err;
+
+ bo = gralloc_drm_bo_from_handle(handle);
+ if (!bo)
+ return -EINVAL;
+
+ return gralloc_drm_bo_lock(bo, usage, x, y, w, h, ptr);
+}
+
+static int drm_mod_unlock(const gralloc_module_t *mod, buffer_handle_t handle)
+{
+ struct drm_module_t *dmod = (struct drm_module_t *) mod;
+ struct gralloc_drm_bo_t *bo;
+
+ bo = gralloc_drm_bo_from_handle(handle);
+ if (!bo)
+ return -EINVAL;
+
+ gralloc_drm_bo_unlock(bo);
+
+ return 0;
+}
+
+static int drm_mod_close_gpu0(struct hw_device_t *dev)
+{
+ struct alloc_device_t *alloc = (struct alloc_device_t *) dev;
+
+ free(alloc);
+
+ return 0;
+}
+
+static int drm_mod_free_gpu0(alloc_device_t *dev, buffer_handle_t handle)
+{
+ struct drm_module_t *dmod = (struct drm_module_t *) dev->common.module;
+ struct gralloc_drm_bo_t *bo;
+
+ bo = gralloc_drm_bo_from_handle(handle);
+ if (!bo)
+ return -EINVAL;
+
+ gralloc_drm_bo_decref(bo);
+
+ return 0;
+}
+
+static int drm_mod_alloc_gpu0(alloc_device_t *dev,
+ int w, int h, int format, int usage,
+ buffer_handle_t *handle, int *stride)
+{
+ struct drm_module_t *dmod = (struct drm_module_t *) dev->common.module;
+ struct gralloc_drm_bo_t *bo;
+ int size, bpp, err;
+
+ bpp = gralloc_drm_get_bpp(format);
+ if (!bpp)
+ return -EINVAL;
+
+ bo = gralloc_drm_bo_create(dmod->drm, w, h, format, usage);
+ if (!bo)
+ return -ENOMEM;
+
+ if (gralloc_drm_bo_need_fb(bo)) {
+ err = gralloc_drm_bo_add_fb(bo);
+ if (err) {
+ ALOGE("failed to add fb");
+ gralloc_drm_bo_decref(bo);
+ return err;
+ }
+ }
+
+ *handle = gralloc_drm_bo_get_handle(bo, stride);
+ /* in pixels */
+ *stride /= bpp;
+
+ return 0;
+}
+
+static int drm_mod_open_gpu0(struct drm_module_t *dmod, hw_device_t **dev)
+{
+ struct alloc_device_t *alloc;
+ int err;
+
+ err = drm_init(dmod, 0);
+ if (err)
+ return err;
+
+ alloc = calloc(1, sizeof(*alloc));
+ if (!alloc)
+ return -EINVAL;
+
+ alloc->common.tag = HARDWARE_DEVICE_TAG;
+ alloc->common.version = 0;
+ alloc->common.module = &dmod->base.common;
+ alloc->common.close = drm_mod_close_gpu0;
+
+ alloc->alloc = drm_mod_alloc_gpu0;
+ alloc->free = drm_mod_free_gpu0;
+
+ *dev = &alloc->common;
+
+ return 0;
+}
+
+static int drm_mod_close_fb0(struct hw_device_t *dev)
+{
+ struct framebuffer_device_t *fb = (struct framebuffer_device_t *) dev;
+
+ free(fb);
+
+ return 0;
+}
+
+static int drm_mod_set_swap_interval_fb0(struct framebuffer_device_t *fb,
+ int interval)
+{
+ if (interval < fb->minSwapInterval || interval > fb->maxSwapInterval)
+ return -EINVAL;
+ return 0;
+}
+
+static int drm_mod_post_fb0(struct framebuffer_device_t *fb,
+ buffer_handle_t handle)
+{
+ struct drm_module_t *dmod = (struct drm_module_t *) fb->common.module;
+ struct gralloc_drm_bo_t *bo;
+
+ bo = gralloc_drm_bo_from_handle(handle);
+ if (!bo)
+ return -EINVAL;
+
+ return gralloc_drm_bo_post(bo);
+}
+
+#include <GLES/gl.h>
+static int drm_mod_composition_complete_fb0(struct framebuffer_device_t *fb)
+{
+ struct drm_module_t *dmod = (struct drm_module_t *) fb->common.module;
+
+ if (gralloc_drm_is_kms_pipelined(dmod->drm))
+ glFlush();
+ else
+ glFinish();
+
+ return 0;
+}
+
+static int drm_mod_open_fb0(struct drm_module_t *dmod, struct hw_device_t **dev)
+{
+ struct framebuffer_device_t *fb;
+ int err;
+
+ err = drm_init(dmod, 1);
+ if (err)
+ return err;
+
+ fb = calloc(1, sizeof(*fb));
+ if (!fb)
+ return -ENOMEM;
+
+ fb->common.tag = HARDWARE_DEVICE_TAG;
+ fb->common.version = 0;
+ fb->common.module = &dmod->base.common;
+ fb->common.close = drm_mod_close_fb0;
+
+ fb->setSwapInterval = drm_mod_set_swap_interval_fb0;
+ fb->post = drm_mod_post_fb0;
+ fb->compositionComplete = drm_mod_composition_complete_fb0;
+
+ gralloc_drm_get_kms_info(dmod->drm, fb);
+
+ *dev = &fb->common;
+
+ ALOGI("mode.hdisplay %d\n"
+ "mode.vdisplay %d\n"
+ "mode.vrefresh %f\n"
+ "format 0x%x\n"
+ "xdpi %f\n"
+ "ydpi %f\n",
+ fb->width,
+ fb->height,
+ fb->fps,
+ fb->format,
+ fb->xdpi, fb->ydpi);
+
+ return 0;
+}
+
+static int drm_mod_open(const struct hw_module_t *mod,
+ const char *name, struct hw_device_t **dev)
+{
+ struct drm_module_t *dmod = (struct drm_module_t *) mod;
+ int err;
+
+ if (strcmp(name, GRALLOC_HARDWARE_GPU0) == 0)
+ err = drm_mod_open_gpu0(dmod, dev);
+ else if (strcmp(name, GRALLOC_HARDWARE_FB0) == 0)
+ err = drm_mod_open_fb0(dmod, dev);
+ else
+ err = -EINVAL;
+
+ return err;
+}
+
+static struct hw_module_methods_t drm_mod_methods = {
+ .open = drm_mod_open
+};
+
+struct drm_module_t HAL_MODULE_INFO_SYM = {
+ .base = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = GRALLOC_HARDWARE_MODULE_ID,
+ .name = "DRM Memory Allocator",
+ .author = "Chia-I Wu",
+ .methods = &drm_mod_methods
+ },
+ .registerBuffer = drm_mod_register_buffer,
+ .unregisterBuffer = drm_mod_unregister_buffer,
+ .lock = drm_mod_lock,
+ .unlock = drm_mod_unlock,
+ .perform = drm_mod_perform
+ },
+ .hwc_reserve_plane = gralloc_drm_reserve_plane,
+ .hwc_disable_planes = gralloc_drm_disable_planes,
+ .hwc_set_plane_handle = gralloc_drm_set_plane_handle,
+
+ .mutex = PTHREAD_MUTEX_INITIALIZER,
+ .drm = NULL
+};
diff --git a/src/drm_gralloc/gralloc_drm.c b/src/drm_gralloc/gralloc_drm.c
new file mode 100644
index 0000000..bd38d57
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm.c
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#define LOG_TAG "GRALLOC-DRM"
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "gralloc_drm.h"
+#include "gralloc_drm_priv.h"
+
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+#define GRALLOC_DRM_DEVICE "/dev/dri/card0"
+
+static int32_t gralloc_drm_pid = 0;
+
+/*
+ * Return the pid of the process.
+ */
+static int gralloc_drm_get_pid(void)
+{
+ if (unlikely(!gralloc_drm_pid))
+ android_atomic_write((int32_t) getpid(), &gralloc_drm_pid);
+
+ return gralloc_drm_pid;
+}
+
+/*
+ * Create the driver for a DRM fd.
+ */
+static struct gralloc_drm_drv_t *
+init_drv_from_fd(int fd)
+{
+ struct gralloc_drm_drv_t *drv = NULL;
+ drmVersionPtr version;
+
+ /* get the kernel module name */
+ version = drmGetVersion(fd);
+ if (!version) {
+ ALOGE("invalid DRM fd");
+ return NULL;
+ }
+
+ if (version->name) {
+#ifdef ENABLE_PIPE
+ drv = gralloc_drm_drv_create_for_pipe(fd, version->name);
+#endif
+
+#ifdef ENABLE_INTEL
+ if (!drv && !strcmp(version->name, "i915"))
+ drv = gralloc_drm_drv_create_for_intel(fd);
+#endif
+#ifdef ENABLE_RADEON
+ if (!drv && !strcmp(version->name, "radeon"))
+ drv = gralloc_drm_drv_create_for_radeon(fd);
+#endif
+#ifdef ENABLE_NOUVEAU
+ if (!drv && !strcmp(version->name, "nouveau"))
+ drv = gralloc_drm_drv_create_for_nouveau(fd);
+#endif
+ }
+
+ if (!drv) {
+ ALOGE("unsupported driver: %s", (version->name) ?
+ version->name : "NULL");
+ }
+
+ drmFreeVersion(version);
+
+ return drv;
+}
+
+/*
+ * Create a DRM device object.
+ */
+struct gralloc_drm_t *gralloc_drm_create(void)
+{
+ struct gralloc_drm_t *drm;
+ int err;
+
+ drm = calloc(1, sizeof(*drm));
+ if (!drm)
+ return NULL;
+
+ drm->fd = open(GRALLOC_DRM_DEVICE, O_RDWR);
+ if (drm->fd < 0) {
+ ALOGE("failed to open %s", GRALLOC_DRM_DEVICE);
+ return NULL;
+ }
+
+ drm->drv = init_drv_from_fd(drm->fd);
+ if (!drm->drv) {
+ close(drm->fd);
+ free(drm);
+ return NULL;
+ }
+
+ return drm;
+}
+
+/*
+ * Destroy a DRM device object.
+ */
+void gralloc_drm_destroy(struct gralloc_drm_t *drm)
+{
+ if (drm->drv)
+ drm->drv->destroy(drm->drv);
+ close(drm->fd);
+ free(drm);
+}
+
+/*
+ * Get the file descriptor of a DRM device object.
+ */
+int gralloc_drm_get_fd(struct gralloc_drm_t *drm)
+{
+ return drm->fd;
+}
+
+/*
+ * Get the magic for authentication.
+ */
+int gralloc_drm_get_magic(struct gralloc_drm_t *drm, int32_t *magic)
+{
+ return drmGetMagic(drm->fd, (drm_magic_t *) magic);
+}
+
+/*
+ * Authenticate a magic.
+ */
+int gralloc_drm_auth_magic(struct gralloc_drm_t *drm, int32_t magic)
+{
+ return drmAuthMagic(drm->fd, (drm_magic_t) magic);
+}
+
+/*
+ * Set as the master of a DRM device.
+ */
+int gralloc_drm_set_master(struct gralloc_drm_t *drm)
+{
+ ALOGD("set master");
+ drmSetMaster(drm->fd);
+ drm->first_post = 1;
+
+ return 0;
+}
+
+/*
+ * Drop from the master of a DRM device.
+ */
+void gralloc_drm_drop_master(struct gralloc_drm_t *drm)
+{
+ drmDropMaster(drm->fd);
+}
+
+/*
+ * Validate a buffer handle and return the associated bo.
+ */
+static struct gralloc_drm_bo_t *validate_handle(buffer_handle_t _handle,
+ struct gralloc_drm_t *drm)
+{
+ struct gralloc_drm_handle_t *handle = gralloc_drm_handle(_handle);
+
+ if (!handle)
+ return NULL;
+
+ /* the buffer handle is passed to a new process */
+ if (unlikely(handle->data_owner != gralloc_drm_pid)) {
+ struct gralloc_drm_bo_t *bo;
+
+ /* check only */
+ if (!drm)
+ return NULL;
+
+ /* create the struct gralloc_drm_bo_t locally */
+ if (handle->name)
+ bo = drm->drv->alloc(drm->drv, handle);
+ else /* an invalid handle */
+ bo = NULL;
+ if (bo) {
+ bo->drm = drm;
+ bo->imported = 1;
+ bo->handle = handle;
+ bo->refcount = 1;
+ }
+
+ handle->data_owner = gralloc_drm_get_pid();
+ handle->data = (int) bo;
+ }
+
+ return (struct gralloc_drm_bo_t *) handle->data;
+}
+
+/*
+ * Register a buffer handle.
+ */
+int gralloc_drm_handle_register(buffer_handle_t handle, struct gralloc_drm_t *drm)
+{
+ return (validate_handle(handle, drm)) ? 0 : -EINVAL;
+}
+
+/*
+ * Unregister a buffer handle. It is no-op for handles created locally.
+ */
+int gralloc_drm_handle_unregister(buffer_handle_t handle)
+{
+ struct gralloc_drm_bo_t *bo;
+
+ bo = validate_handle(handle, NULL);
+ if (!bo)
+ return -EINVAL;
+
+ if (bo->imported)
+ gralloc_drm_bo_decref(bo);
+
+ return 0;
+}
+
+/*
+ * Create a buffer handle.
+ */
+static struct gralloc_drm_handle_t *create_bo_handle(int width,
+ int height, int format, int usage)
+{
+ struct gralloc_drm_handle_t *handle;
+
+ handle = calloc(1, sizeof(*handle));
+ if (!handle)
+ return NULL;
+
+ handle->base.version = sizeof(handle->base);
+ handle->base.numInts = GRALLOC_DRM_HANDLE_NUM_INTS;
+ handle->base.numFds = GRALLOC_DRM_HANDLE_NUM_FDS;
+
+ handle->magic = GRALLOC_DRM_HANDLE_MAGIC;
+ handle->width = width;
+ handle->height = height;
+ handle->format = format;
+ handle->usage = usage;
+ handle->plane_mask = 0;
+
+ return handle;
+}
+
+/*
+ * Create a bo.
+ */
+struct gralloc_drm_bo_t *gralloc_drm_bo_create(struct gralloc_drm_t *drm,
+ int width, int height, int format, int usage)
+{
+ struct gralloc_drm_bo_t *bo;
+ struct gralloc_drm_handle_t *handle;
+
+ handle = create_bo_handle(width, height, format, usage);
+ if (!handle)
+ return NULL;
+
+ handle->plane_mask = planes_for_format(drm, format);
+
+ bo = drm->drv->alloc(drm->drv, handle);
+ if (!bo) {
+ free(handle);
+ return NULL;
+ }
+
+ bo->drm = drm;
+ bo->imported = 0;
+ bo->handle = handle;
+ bo->fb_id = 0;
+ bo->refcount = 1;
+
+ handle->data_owner = gralloc_drm_get_pid();
+ handle->data = (int) bo;
+
+ return bo;
+}
+
+/*
+ * Destroy a bo.
+ */
+static void gralloc_drm_bo_destroy(struct gralloc_drm_bo_t *bo)
+{
+ struct gralloc_drm_handle_t *handle = bo->handle;
+ int imported = bo->imported;
+
+ /* gralloc still has a reference */
+ if (bo->refcount)
+ return;
+
+ gralloc_drm_bo_rm_fb(bo);
+
+ bo->drm->drv->free(bo->drm->drv, bo);
+ if (imported) {
+ handle->data_owner = 0;
+ handle->data = 0;
+ }
+ else {
+ free(handle);
+ }
+}
+
+/*
+ * Decrease refcount, if no refs anymore then destroy.
+ */
+void gralloc_drm_bo_decref(struct gralloc_drm_bo_t *bo)
+{
+ if (!--bo->refcount)
+ gralloc_drm_bo_destroy(bo);
+}
+
+/*
+ * Return the bo of a registered handle.
+ */
+struct gralloc_drm_bo_t *gralloc_drm_bo_from_handle(buffer_handle_t handle)
+{
+ return validate_handle(handle, NULL);
+}
+
+/*
+ * Get the buffer handle and stride of a bo.
+ */
+buffer_handle_t gralloc_drm_bo_get_handle(struct gralloc_drm_bo_t *bo, int *stride)
+{
+ if (stride)
+ *stride = bo->handle->stride;
+ return &bo->handle->base;
+}
+
+int gralloc_drm_get_gem_handle(buffer_handle_t _handle)
+{
+ struct gralloc_drm_handle_t *handle = gralloc_drm_handle(_handle);
+ return (handle) ? handle->name : 0;
+}
+
+/*
+ * Query YUV component offsets for a buffer handle
+ */
+void gralloc_drm_resolve_format(buffer_handle_t _handle,
+ uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
+{
+ struct gralloc_drm_handle_t *handle = gralloc_drm_handle(_handle);
+ struct gralloc_drm_bo_t *bo = (struct gralloc_drm_bo_t *) handle->data;
+ struct gralloc_drm_t *drm = bo->drm;
+
+ /* if handle exists and driver implements resolve_format */
+ if (handle && drm->drv->resolve_format)
+ drm->drv->resolve_format(drm->drv, bo,
+ pitches, offsets, handles);
+}
+
+/*
+ * Lock a bo. XXX thread-safety?
+ */
+int gralloc_drm_bo_lock(struct gralloc_drm_bo_t *bo,
+ int usage, int x, int y, int w, int h,
+ void **addr)
+{
+ if ((bo->handle->usage & usage) != usage) {
+ /* make FB special for testing software renderer with */
+
+ if (!(bo->handle->usage & GRALLOC_USAGE_HW_FB)
+ && !(bo->handle->usage & GRALLOC_USAGE_HW_TEXTURE)) {
+ ALOGE("bo.usage:x%X/usage:x%X is not GRALLOC_USAGE_HW_FB or GRALLOC_USAGE_HW_TEXTURE"
+ ,bo->handle->usage,usage);
+ return -EINVAL;
+ }
+ }
+
+ /* allow multiple locks with compatible usages */
+ if (bo->lock_count && (bo->locked_for & usage) != usage)
+ return -EINVAL;
+
+ usage |= bo->locked_for;
+
+ if (usage & (GRALLOC_USAGE_SW_WRITE_MASK |
+ GRALLOC_USAGE_SW_READ_MASK)) {
+ /* the driver is supposed to wait for the bo */
+ int write = !!(usage & GRALLOC_USAGE_SW_WRITE_MASK);
+ int err = bo->drm->drv->map(bo->drm->drv, bo,
+ x, y, w, h, write, addr);
+ if (err)
+ return err;
+ }
+ else {
+ /* kernel handles the synchronization here */
+ }
+
+ bo->lock_count++;
+ bo->locked_for |= usage;
+
+ return 0;
+}
+
+/*
+ * Unlock a bo.
+ */
+void gralloc_drm_bo_unlock(struct gralloc_drm_bo_t *bo)
+{
+ int mapped = bo->locked_for &
+ (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_SW_READ_MASK);
+
+ if (!bo->lock_count)
+ return;
+
+ if (mapped)
+ bo->drm->drv->unmap(bo->drm->drv, bo);
+
+ bo->lock_count--;
+ if (!bo->lock_count)
+ bo->locked_for = 0;
+}
diff --git a/src/drm_gralloc/gralloc_drm.h b/src/drm_gralloc/gralloc_drm.h
new file mode 100644
index 0000000..c32aaf6
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _GRALLOC_DRM_H_
+#define _GRALLOC_DRM_H_
+
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1))
+
+struct gralloc_drm_t;
+struct gralloc_drm_bo_t;
+
+struct gralloc_drm_t *gralloc_drm_create(void);
+void gralloc_drm_destroy(struct gralloc_drm_t *drm);
+
+int gralloc_drm_get_fd(struct gralloc_drm_t *drm);
+int gralloc_drm_get_magic(struct gralloc_drm_t *drm, int32_t *magic);
+int gralloc_drm_auth_magic(struct gralloc_drm_t *drm, int32_t magic);
+int gralloc_drm_set_master(struct gralloc_drm_t *drm);
+void gralloc_drm_drop_master(struct gralloc_drm_t *drm);
+
+int gralloc_drm_init_kms(struct gralloc_drm_t *drm);
+void gralloc_drm_fini_kms(struct gralloc_drm_t *drm);
+int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm);
+
+void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm, struct framebuffer_device_t *fb);
+int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm);
+
+static inline int gralloc_drm_get_bpp(int format)
+{
+ int bpp;
+
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ bpp = 4;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ bpp = 3;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ bpp = 2;
+ break;
+ /* planar; only Y is considered */
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_DRM_NV12:
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ bpp = 1;
+ break;
+ default:
+ bpp = 0;
+ break;
+ }
+
+ return bpp;
+}
+
+static inline void gralloc_drm_align_geometry(int format, int *width, int *height)
+{
+ int align_w = 1, align_h = 1, extra_height_div = 0;
+
+ switch (format) {
+ case HAL_PIXEL_FORMAT_DRM_NV12:
+ case HAL_PIXEL_FORMAT_YV12:
+ align_w = 32;
+ align_h = 2;
+ extra_height_div = 2;
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ align_w = 2;
+ extra_height_div = 1;
+ break;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ align_w = 2;
+ align_h = 2;
+ extra_height_div = 2;
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ align_w = 2;
+ break;
+ }
+
+ *width = ALIGN(*width, align_w);
+ *height = ALIGN(*height, align_h);
+
+ if (extra_height_div)
+ *height += *height / extra_height_div;
+}
+
+int gralloc_drm_handle_register(buffer_handle_t handle, struct gralloc_drm_t *drm);
+int gralloc_drm_handle_unregister(buffer_handle_t handle);
+
+struct gralloc_drm_bo_t *gralloc_drm_bo_create(struct gralloc_drm_t *drm, int width, int height, int format, int usage);
+void gralloc_drm_bo_decref(struct gralloc_drm_bo_t *bo);
+
+struct gralloc_drm_bo_t *gralloc_drm_bo_from_handle(buffer_handle_t handle);
+buffer_handle_t gralloc_drm_bo_get_handle(struct gralloc_drm_bo_t *bo, int *stride);
+int gralloc_drm_get_gem_handle(buffer_handle_t handle);
+void gralloc_drm_resolve_format(buffer_handle_t _handle, uint32_t *pitches, uint32_t *offsets, uint32_t *handles);
+unsigned int planes_for_format(struct gralloc_drm_t *drm, int hal_format);
+
+int gralloc_drm_bo_lock(struct gralloc_drm_bo_t *bo, int x, int y, int w, int h, int enable_write, void **addr);
+void gralloc_drm_bo_unlock(struct gralloc_drm_bo_t *bo);
+
+int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo);
+int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo);
+void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo);
+int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo);
+
+int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
+ buffer_handle_t handle, uint32_t id,
+ uint32_t dst_x, uint32_t dst_y, uint32_t dst_w, uint32_t dst_h,
+ uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h);
+void gralloc_drm_disable_planes(struct gralloc_drm_t *mod);
+int gralloc_drm_set_plane_handle(struct gralloc_drm_t *drm,
+ uint32_t id, buffer_handle_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _GRALLOC_DRM_H_ */
diff --git a/src/drm_gralloc/gralloc_drm_handle.h b/src/drm_gralloc/gralloc_drm_handle.h
new file mode 100644
index 0000000..f7b03b2
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm_handle.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _GRALLOC_DRM_HANDLE_H_
+#define _GRALLOC_DRM_HANDLE_H_
+
+#include <cutils/native_handle.h>
+#include <system/graphics.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct gralloc_drm_handle_t {
+ native_handle_t base;
+
+#define GRALLOC_DRM_HANDLE_MAGIC 0x12345678
+#define GRALLOC_DRM_HANDLE_NUM_INTS 10
+#define GRALLOC_DRM_HANDLE_NUM_FDS 0
+ int magic;
+
+ int width;
+ int height;
+ int format;
+ int usage;
+
+ unsigned int plane_mask; /* planes that support handle */
+
+ int name; /* the name of the bo */
+ int stride; /* the stride in bytes */
+
+ int data_owner; /* owner of data (for validation) */
+ int data; /* pointer to struct gralloc_drm_bo_t */
+};
+
+static inline struct gralloc_drm_handle_t *gralloc_drm_handle(buffer_handle_t _handle)
+{
+ struct gralloc_drm_handle_t *handle =
+ (struct gralloc_drm_handle_t *) _handle;
+
+ if (handle && (handle->base.version != sizeof(handle->base) ||
+ handle->base.numInts != GRALLOC_DRM_HANDLE_NUM_INTS ||
+ handle->base.numFds != GRALLOC_DRM_HANDLE_NUM_FDS ||
+ handle->magic != GRALLOC_DRM_HANDLE_MAGIC))
+ handle = NULL;
+
+ return handle;
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _GRALLOC_DRM_HANDLE_H_ */
diff --git a/src/drm_gralloc/gralloc_drm_intel.c b/src/drm_gralloc/gralloc_drm_intel.c
new file mode 100644
index 0000000..3a020b4
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm_intel.c
@@ -0,0 +1,676 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ *
+ * drm_gem_intel_copy is based on xorg-driver-intel, which has
+ *
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * Copyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#define LOG_TAG "GRALLOC-I915"
+
+#include <cutils/log.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <drm.h>
+#include <intel_bufmgr.h>
+#include <i915_drm.h>
+
+#include "gralloc_drm.h"
+#include "gralloc_drm_priv.h"
+
+#define MI_NOOP (0)
+#define MI_BATCH_BUFFER_END (0x0a << 23)
+#define MI_FLUSH (0x04 << 23)
+#define MI_FLUSH_DW (0x26 << 23)
+#define MI_WRITE_DIRTY_STATE (1 << 4)
+#define MI_INVALIDATE_MAP_CACHE (1 << 0)
+#define XY_SRC_COPY_BLT_CMD ((2 << 29) | (0x53 << 22) | 6)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA (1 << 21)
+#define XY_SRC_COPY_BLT_WRITE_RGB (1 << 20)
+#define XY_SRC_COPY_BLT_SRC_TILED (1 << 15)
+#define XY_SRC_COPY_BLT_DST_TILED (1 << 11)
+
+struct intel_info {
+ struct gralloc_drm_drv_t base;
+
+ int fd;
+ drm_intel_bufmgr *bufmgr;
+ int gen;
+
+ drm_intel_bo *batch_ibo;
+ uint32_t *batch, *cur;
+ int capacity, size;
+ int exec_blt;
+};
+
+struct intel_buffer {
+ struct gralloc_drm_bo_t base;
+ drm_intel_bo *ibo;
+ uint32_t tiling;
+};
+
+static int
+batch_next(struct intel_info *info)
+{
+ info->cur = info->batch;
+
+ if (info->batch_ibo)
+ drm_intel_bo_unreference(info->batch_ibo);
+
+ info->batch_ibo = drm_intel_bo_alloc(info->bufmgr,
+ "gralloc-batchbuffer", info->size, 4096);
+
+ return (info->batch_ibo) ? 0 : -ENOMEM;
+}
+
+static int
+batch_count(struct intel_info *info)
+{
+ return info->cur - info->batch;
+}
+
+static void
+batch_dword(struct intel_info *info, uint32_t dword)
+{
+ *info->cur++ = dword;
+}
+
+static int
+batch_reloc(struct intel_info *info, struct gralloc_drm_bo_t *bo,
+ uint32_t read_domains, uint32_t write_domain)
+{
+ struct intel_buffer *target = (struct intel_buffer *) bo;
+ uint32_t offset = (info->cur - info->batch) * sizeof(info->batch[0]);
+ int ret;
+
+ ret = drm_intel_bo_emit_reloc(info->batch_ibo, offset,
+ target->ibo, 0, read_domains, write_domain);
+ if (!ret)
+ batch_dword(info, target->ibo->offset);
+
+ return ret;
+}
+
+static int
+batch_flush(struct intel_info *info)
+{
+ int size, ret;
+
+ batch_dword(info, MI_BATCH_BUFFER_END);
+ size = batch_count(info);
+ if (size & 1) {
+ batch_dword(info, MI_NOOP);
+ size = batch_count(info);
+ }
+
+ size *= sizeof(info->batch[0]);
+ ret = drm_intel_bo_subdata(info->batch_ibo, 0, size, info->batch);
+ if (ret) {
+ ALOGE("failed to subdata batch");
+ goto fail;
+ }
+ ret = drm_intel_bo_mrb_exec(info->batch_ibo, size,
+ NULL, 0, 0, info->exec_blt);
+ if (ret) {
+ ALOGE("failed to exec batch");
+ goto fail;
+ }
+
+ return batch_next(info);
+
+fail:
+ info->cur = info->batch;
+
+ return ret;
+}
+
+static int
+batch_reserve(struct intel_info *info, int count)
+{
+ int ret = 0;
+
+ if (batch_count(info) + count > info->capacity)
+ ret = batch_flush(info);
+
+ return ret;
+}
+
+static void
+batch_destroy(struct intel_info *info)
+{
+ if (info->batch_ibo) {
+ drm_intel_bo_unreference(info->batch_ibo);
+ info->batch_ibo = NULL;
+ }
+
+ if (info->batch) {
+ free(info->batch);
+ info->batch = NULL;
+ }
+}
+
+static int
+batch_init(struct intel_info *info)
+{
+ int ret;
+
+ info->capacity = 512;
+ info->size = (info->capacity + 16) * sizeof(info->batch[0]);
+
+ info->batch = malloc(info->size);
+ if (!info->batch)
+ return -ENOMEM;
+
+ ret = batch_next(info);
+ if (ret) {
+ free(info->batch);
+ info->batch = NULL;
+ }
+
+ return ret;
+}
+
+static void intel_resolve_format(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo,
+ uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
+{
+ /*
+ * TODO - should take account hw specific padding, alignment
+ * for camera, video decoder etc.
+ */
+
+ struct intel_buffer *ib = (struct intel_buffer *) bo;
+
+ memset(pitches, 0, 4 * sizeof(uint32_t));
+ memset(offsets, 0, 4 * sizeof(uint32_t));
+ memset(handles, 0, 4 * sizeof(uint32_t));
+
+ pitches[0] = ib->base.handle->stride;
+ handles[0] = ib->base.fb_handle;
+
+ switch(ib->base.handle->format) {
+ case HAL_PIXEL_FORMAT_YV12:
+
+ // U and V stride are half of Y plane
+ pitches[2] = pitches[0]/2;
+ pitches[1] = pitches[0]/2;
+
+ // like I420 but U and V are in reverse order
+ offsets[2] = offsets[0] +
+ pitches[0] * ib->base.handle->height;
+ offsets[1] = offsets[2] +
+ pitches[2] * ib->base.handle->height/2;
+
+ handles[1] = handles[2] = handles[0];
+ break;
+
+ case HAL_PIXEL_FORMAT_DRM_NV12:
+
+ // U and V are interleaved in 2nd plane
+ pitches[1] = pitches[0];
+ offsets[1] = offsets[0] +
+ pitches[0] * ib->base.handle->height;
+
+ handles[1] = handles[0];
+ break;
+ }
+}
+
+
+static void intel_blit(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *dst,
+ struct gralloc_drm_bo_t *src,
+ uint16_t dst_x1, uint16_t dst_y1,
+ uint16_t dst_x2, uint16_t dst_y2,
+ uint16_t src_x1, uint16_t src_y1,
+ uint16_t src_x2, uint16_t src_y2)
+{
+ struct intel_info *info = (struct intel_info *) drv;
+ struct intel_buffer *dst_ib = (struct intel_buffer *) dst;
+ struct intel_buffer *src_ib = (struct intel_buffer *) src;
+ drm_intel_bo *bo_table[3];
+ uint32_t cmd, br13, dst_pitch, src_pitch;
+
+ /*
+ * XY_SRC_COPY_BLT_CMD does not support scaling,
+ * rectangle dimensions much match
+ */
+ if (src_x2 - src_x1 != dst_x2 - dst_x1 ||
+ src_y2 - src_y1 != dst_y2 - dst_y1) {
+ ALOGE("%s, src and dst rect must match", __func__);
+ return;
+ }
+
+ if (dst->handle->format != src->handle->format) {
+ ALOGE("%s, src and dst format must match", __func__);
+ return;
+ }
+
+ /* nothing to blit */
+ if (src_x2 <= src_x1 || src_y2 <= src_y1)
+ return;
+
+ /* clamp x2, y2 to surface size */
+ if (src_x2 > src->handle->width)
+ src_x2 = src->handle->width;
+ if (src_y2 > src->handle->height)
+ src_y2 = src->handle->height;
+
+ if (dst_x2 > dst->handle->width)
+ dst_x2 = dst->handle->width;
+ if (dst_y2 > dst->handle->height)
+ dst_y2 = dst->handle->height;
+
+ bo_table[0] = info->batch_ibo;
+ bo_table[1] = src_ib->ibo;
+ bo_table[2] = dst_ib->ibo;
+ if (drm_intel_bufmgr_check_aperture_space(bo_table, 3)) {
+ if (batch_flush(info))
+ return;
+ assert(!drm_intel_bufmgr_check_aperture_space(bo_table, 3));
+ }
+
+ cmd = XY_SRC_COPY_BLT_CMD;
+ br13 = 0xcc << 16; /* ROP_S/GXcopy */
+ dst_pitch = dst->handle->stride;
+ src_pitch = src->handle->stride;
+
+ /* Blit pitch must be dword-aligned. Otherwise, the hardware appears to
+ * drop the low bits.
+ */
+ if (src_pitch % 4 != 0 || dst_pitch % 4 != 0) {
+ ALOGE("%s, src and dst pitch must be dword aligned", __func__);
+ return;
+ }
+
+ switch (gralloc_drm_get_bpp(dst->handle->format)) {
+ case 1:
+ break;
+ case 2:
+ br13 |= (1 << 24);
+ break;
+ case 4:
+ br13 |= (1 << 24) | (1 << 25);
+ cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
+ break;
+ default:
+ ALOGE("%s, copy with unsupported format", __func__);
+ return;
+ }
+
+ if (info->gen >= 40) {
+ if (dst_ib->tiling != I915_TILING_NONE) {
+ assert(dst_pitch % 512 == 0);
+ dst_pitch >>= 2;
+ cmd |= XY_SRC_COPY_BLT_DST_TILED;
+ }
+ if (src_ib->tiling != I915_TILING_NONE) {
+ assert(src_pitch % 512 == 0);
+ src_pitch >>= 2;
+ cmd |= XY_SRC_COPY_BLT_SRC_TILED;
+ }
+ }
+
+ if (batch_reserve(info, 8))
+ return;
+
+ batch_dword(info, cmd);
+ batch_dword(info, br13 | (uint16_t)dst_pitch);
+ batch_dword(info, (dst_y1 << 16) | dst_x1);
+ batch_dword(info, (dst_y2 << 16) | dst_x2);
+ batch_reloc(info, dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+ batch_dword(info, (src_y1 << 16) | src_x1);
+ batch_dword(info, (uint16_t)src_pitch);
+ batch_reloc(info, src, I915_GEM_DOMAIN_RENDER, 0);
+
+ if (info->gen >= 60) {
+ batch_reserve(info, 4);
+ batch_dword(info, MI_FLUSH_DW | 2);
+ batch_dword(info, 0);
+ batch_dword(info, 0);
+ batch_dword(info, 0);
+ }
+ else {
+ int flags = (info->gen >= 40) ? 0 :
+ MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE;
+
+ batch_reserve(info, 1);
+ batch_dword(info, MI_FLUSH | flags);
+ }
+
+ batch_flush(info);
+}
+
+static drm_intel_bo *alloc_ibo(struct intel_info *info,
+ const struct gralloc_drm_handle_t *handle,
+ uint32_t *tiling, unsigned long *stride)
+{
+ drm_intel_bo *ibo;
+ const char *name;
+ int aligned_width, aligned_height, bpp;
+ unsigned long flags;
+
+ flags = 0;
+ bpp = gralloc_drm_get_bpp(handle->format);
+ if (!bpp) {
+ ALOGE("unrecognized format 0x%x", handle->format);
+ return NULL;
+ }
+
+ aligned_width = handle->width;
+ aligned_height = handle->height;
+ gralloc_drm_align_geometry(handle->format,
+ &aligned_width, &aligned_height);
+
+ if (handle->usage & GRALLOC_USAGE_HW_FB) {
+ unsigned long max_stride;
+
+ max_stride = 32 * 1024;
+ if (info->gen < 50)
+ max_stride /= 2;
+ if (info->gen < 40)
+ max_stride /= 2;
+
+ name = "gralloc-fb";
+ aligned_width = ALIGN(aligned_width, 64);
+ flags = BO_ALLOC_FOR_RENDER;
+
+ *tiling = I915_TILING_X;
+ *stride = aligned_width * bpp;
+ if (*stride > max_stride) {
+ *tiling = I915_TILING_NONE;
+ max_stride = 32 * 1024;
+ if (*stride > max_stride)
+ return NULL;
+ }
+
+ while (1) {
+ ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
+ aligned_width, aligned_height,
+ bpp, tiling, stride, flags);
+ if (!ibo || *stride > max_stride) {
+ if (ibo) {
+ drm_intel_bo_unreference(ibo);
+ ibo = NULL;
+ }
+
+ if (*tiling != I915_TILING_NONE) {
+ /* retry */
+ *tiling = I915_TILING_NONE;
+ max_stride = 32 * 1024;
+ continue;
+ }
+ }
+ if (ibo)
+ drm_intel_bo_disable_reuse(ibo);
+ break;
+ }
+ }
+ else {
+ if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN))
+ *tiling = I915_TILING_NONE;
+ else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) ||
+ ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) &&
+ handle->width >= 64))
+ *tiling = I915_TILING_X;
+ else
+ *tiling = I915_TILING_NONE;
+
+ if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) {
+ name = "gralloc-texture";
+ /* see 2D texture layout of DRI drivers */
+ aligned_width = ALIGN(aligned_width, 4);
+ aligned_height = ALIGN(aligned_height, 2);
+ }
+ else {
+ name = "gralloc-buffer";
+ }
+
+ if (handle->usage & GRALLOC_USAGE_HW_RENDER)
+ flags = BO_ALLOC_FOR_RENDER;
+
+ ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
+ aligned_width, aligned_height,
+ bpp, tiling, stride, flags);
+ }
+
+ return ibo;
+}
+
+static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_handle_t *handle)
+{
+ struct intel_info *info = (struct intel_info *) drv;
+ struct intel_buffer *ib;
+
+ ib = calloc(1, sizeof(*ib));
+ if (!ib)
+ return NULL;
+
+ if (handle->name) {
+ uint32_t dummy;
+
+ ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr,
+ "gralloc-r", handle->name);
+ if (!ib->ibo) {
+ ALOGE("failed to create ibo from name %u",
+ handle->name);
+ free(ib);
+ return NULL;
+ }
+
+ if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) {
+ ALOGE("failed to get ibo tiling");
+ drm_intel_bo_unreference(ib->ibo);
+ free(ib);
+ return NULL;
+ }
+ }
+ else {
+ unsigned long stride;
+
+ ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride);
+ if (!ib->ibo) {
+ ALOGE("failed to allocate ibo %dx%d (format %d)",
+ handle->width,
+ handle->height,
+ handle->format);
+ free(ib);
+ return NULL;
+ }
+
+ handle->stride = stride;
+
+ if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) {
+ ALOGE("failed to flink ibo");
+ drm_intel_bo_unreference(ib->ibo);
+ free(ib);
+ return NULL;
+ }
+ }
+
+ ib->base.fb_handle = ib->ibo->handle;
+
+ ib->base.handle = handle;
+
+ return &ib->base;
+}
+
+static void intel_free(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo)
+{
+ struct intel_buffer *ib = (struct intel_buffer *) bo;
+
+ drm_intel_bo_unreference(ib->ibo);
+ free(ib);
+}
+
+static int intel_map(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo,
+ int x, int y, int w, int h,
+ int enable_write, void **addr)
+{
+ struct intel_buffer *ib = (struct intel_buffer *) bo;
+ int err;
+
+ if (ib->tiling != I915_TILING_NONE ||
+ (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
+ err = drm_intel_gem_bo_map_gtt(ib->ibo);
+ else
+ err = drm_intel_bo_map(ib->ibo, enable_write);
+ if (!err)
+ *addr = ib->ibo->virtual;
+
+ return err;
+}
+
+static void intel_unmap(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo)
+{
+ struct intel_buffer *ib = (struct intel_buffer *) bo;
+
+ if (ib->tiling != I915_TILING_NONE ||
+ (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
+ drm_intel_gem_bo_unmap_gtt(ib->ibo);
+ else
+ drm_intel_bo_unmap(ib->ibo);
+}
+
+#include "intel_chipset.h" /* for platform detection macros */
+static void intel_init_kms_features(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_t *drm)
+{
+ struct intel_info *info = (struct intel_info *) drv;
+ struct drm_i915_getparam gp;
+ int pageflipping, id, has_blt;
+
+ switch (drm->primary.fb_format) {
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ break;
+ default:
+ drm->primary.fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
+ break;
+ }
+
+ drm->mode_quirk_vmwgfx = 0;
+ /* why? */
+ drm->mode_sync_flip = 1;
+
+ memset(&gp, 0, sizeof(gp));
+ gp.param = I915_PARAM_HAS_PAGEFLIPPING;
+ gp.value = &pageflipping;
+ if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
+ pageflipping = 0;
+
+ memset(&gp, 0, sizeof(gp));
+ gp.param = I915_PARAM_CHIPSET_ID;
+ gp.value = &id;
+ if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
+ id = 0;
+
+ memset(&gp, 0, sizeof(gp));
+ gp.param = I915_PARAM_HAS_BLT;
+ gp.value = &has_blt;
+ if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
+ has_blt = 0;
+ info->exec_blt = has_blt ? I915_EXEC_BLT : 0;
+
+ /* GEN4, G4X, GEN5, GEN6, GEN7 */
+ if ((IS_9XX(id) || IS_G4X(id)) && !IS_GEN3(id)) {
+ if (IS_GEN7(id))
+ info->gen = 70;
+ else if (IS_GEN6(id))
+ info->gen = 60;
+ else if (IS_GEN5(id))
+ info->gen = 50;
+ else
+ info->gen = 40;
+ }
+ else {
+ info->gen = 30;
+ }
+
+ if (pageflipping && info->gen > 30)
+ drm->swap_mode = DRM_SWAP_FLIP;
+ else if (info->batch && info->gen == 30)
+ drm->swap_mode = DRM_SWAP_COPY;
+ else
+ drm->swap_mode = DRM_SWAP_SETCRTC;
+
+ if (drm->resources) {
+ int pipe;
+
+ pipe = drm_intel_get_pipe_from_crtc_id(info->bufmgr,
+ drm->primary.crtc_id);
+ drm->swap_interval = (pipe >= 0) ? 1 : 0;
+ drm->vblank_secondary = (pipe > 0);
+ }
+ else {
+ drm->swap_interval = 0;
+ }
+}
+
+static void intel_destroy(struct gralloc_drm_drv_t *drv)
+{
+ struct intel_info *info = (struct intel_info *) drv;
+
+ batch_destroy(info);
+ drm_intel_bufmgr_destroy(info->bufmgr);
+ free(info);
+}
+
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd)
+{
+ struct intel_info *info;
+
+ info = calloc(1, sizeof(*info));
+ if (!info) {
+ ALOGE("failed to allocate driver info");
+ return NULL;
+ }
+
+ info->fd = fd;
+ info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024);
+ if (!info->bufmgr) {
+ ALOGE("failed to create buffer manager");
+ free(info);
+ return NULL;
+ }
+
+ batch_init(info);
+
+ info->base.destroy = intel_destroy;
+ info->base.init_kms_features = intel_init_kms_features;
+ info->base.alloc = intel_alloc;
+ info->base.free = intel_free;
+ info->base.map = intel_map;
+ info->base.unmap = intel_unmap;
+ info->base.blit = intel_blit;
+ info->base.resolve_format = intel_resolve_format;
+
+ return &info->base;
+}
diff --git a/src/drm_gralloc/gralloc_drm_kms.c b/src/drm_gralloc/gralloc_drm_kms.c
new file mode 100644
index 0000000..0909361
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm_kms.c
@@ -0,0 +1,1259 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#define LOG_TAG "GRALLOC-KMS"
+
+#include <cutils/properties.h>
+#include <cutils/log.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <poll.h>
+#include <math.h>
+#include "gralloc_drm.h"
+#include "gralloc_drm_priv.h"
+#include <hardware_legacy/uevent.h>
+
+#include <drm_fourcc.h>
+
+/*
+ * Return true if a bo needs fb.
+ */
+int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
+{
+ return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
+ bo->drm->swap_mode != DRM_SWAP_COPY);
+}
+
+static unsigned int drm_format_from_hal(int hal_format)
+{
+ switch(hal_format) {
+ case HAL_PIXEL_FORMAT_RGB_888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return DRM_FORMAT_XRGB8888;
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ return DRM_FORMAT_XBGR8888;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ return DRM_FORMAT_RGBA8888;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return DRM_FORMAT_RGB565;
+ case HAL_PIXEL_FORMAT_YV12:
+ return DRM_FORMAT_YUV420;
+ case HAL_PIXEL_FORMAT_DRM_NV12:
+ return DRM_FORMAT_NV12;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Modify pitches, offsets and handles according to
+ * the format and return corresponding drm format value
+ */
+static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
+ uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
+{
+ struct gralloc_drm_t *drm = bo->drm;
+
+ pitches[0] = bo->handle->stride;
+ handles[0] = bo->fb_handle;
+
+ /* driver takes care of HW specific padding, alignment etc. */
+ if (drm->drv->resolve_format)
+ drm->drv->resolve_format(drm->drv, bo,
+ pitches, offsets, handles);
+
+ return drm_format_from_hal(bo->handle->format);
+}
+
+/*
+ * Returns planes that are supported for a particular format
+ */
+unsigned int planes_for_format(struct gralloc_drm_t *drm,
+ int hal_format)
+{
+ unsigned int i, j, mask = 0;
+ unsigned int drm_format = drm_format_from_hal(hal_format);
+ struct gralloc_drm_plane_t *plane = drm->planes;
+
+ /* no planes available */
+ if (!plane)
+ return 0;
+
+ /* iterate through planes, mark those that match format */
+ for (i=0; i<drm->plane_resources->count_planes; i++, plane++)
+ for (j=0; j<plane->drm_plane->count_formats; j++)
+ if (plane->drm_plane->formats[j] == drm_format)
+ mask |= (1U << plane->drm_plane->plane_id);
+
+ return mask;
+}
+
+/*
+ * Add a fb object for a bo.
+ */
+int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
+{
+ uint32_t pitches[4] = { 0, 0, 0, 0 };
+ uint32_t offsets[4] = { 0, 0, 0, 0 };
+ uint32_t handles[4] = { 0, 0, 0, 0 };
+
+ if (bo->fb_id)
+ return 0;
+
+ int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
+
+ if (drm_format == 0) {
+ ALOGE("error resolving drm format");
+ return -EINVAL;
+ }
+
+ return drmModeAddFB2(bo->drm->fd,
+ bo->handle->width, bo->handle->height,
+ drm_format, handles, pitches, offsets,
+ (uint32_t *) &bo->fb_id, 0);
+}
+
+/*
+ * Remove a fb object for a bo.
+ */
+void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
+{
+ if (bo->fb_id) {
+ drmModeRmFB(bo->drm->fd, bo->fb_id);
+ bo->fb_id = 0;
+ }
+}
+
+/*
+ * Program CRTC.
+ */
+static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
+ struct gralloc_drm_output *output, int fb_id)
+{
+ int ret;
+
+ ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
+ 0, 0, &output->connector_id, 1, &output->mode);
+ if (ret) {
+ ALOGE("failed to set crtc (%s) (crtc_id %d, fb_id %d, conn %d, mode %dx%d)",
+ strerror(errno), output->crtc_id, fb_id, output->connector_id,
+ output->mode.hdisplay, output->mode.vdisplay);
+ return ret;
+ }
+
+ if (drm->mode_quirk_vmwgfx)
+ ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
+
+ return ret;
+}
+
+/*
+ * Callback for a page flip event.
+ */
+static void page_flip_handler(int fd, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec,
+ void *user_data)
+{
+ struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
+
+ /* ack the last scheduled flip */
+ drm->current_front = drm->next_front;
+ drm->next_front = NULL;
+}
+
+/*
+ * Set a plane.
+ */
+static int gralloc_drm_bo_setplane(struct gralloc_drm_t *drm,
+ struct gralloc_drm_plane_t *plane)
+{
+ struct gralloc_drm_bo_t *bo = NULL;
+ int err;
+
+ if (plane->handle)
+ bo = gralloc_drm_bo_from_handle(plane->handle);
+
+ // create a framebuffer if does not exist
+ if (bo && bo->fb_id == 0) {
+ err = gralloc_drm_bo_add_fb(bo);
+ if (err) {
+ ALOGE("%s: could not create drm fb, (%s)",
+ __func__, strerror(-err));
+ return err;
+ }
+ }
+
+ err = drmModeSetPlane(drm->fd,
+ plane->drm_plane->plane_id,
+ drm->primary.crtc_id,
+ bo ? bo->fb_id : 0,
+ 0, // flags
+ plane->dst_x,
+ plane->dst_y,
+ plane->dst_w,
+ plane->dst_h,
+ plane->src_x << 16,
+ plane->src_y << 16,
+ plane->src_w << 16,
+ plane->src_h << 16);
+
+ if (err) {
+ /* clear plane_mask so that this buffer won't be tried again */
+ struct gralloc_drm_handle_t *drm_handle =
+ (struct gralloc_drm_handle_t *) plane->handle;
+ drm_handle->plane_mask = 0;
+
+ ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
+ strerror(-err),
+ plane->drm_plane->plane_id,
+ drm->primary.crtc_id,
+ bo ? bo->fb_id : 0);
+ }
+
+ if (plane->prev)
+ gralloc_drm_bo_decref(plane->prev);
+
+ if (bo)
+ bo->refcount++;
+
+ plane->prev = bo;
+
+ return err;
+}
+
+/*
+ * Returns if a particular plane is supported with the implementation
+ */
+static unsigned is_plane_supported(const struct gralloc_drm_t *drm,
+ const struct gralloc_drm_plane_t *plane)
+{
+ /* Planes are only supported on primary pipe for now */
+ return plane->drm_plane->possible_crtcs & (1 << drm->primary.pipe);
+}
+
+/*
+ * Sets all the active planes to be displayed.
+ */
+static void gralloc_drm_set_planes(struct gralloc_drm_t *drm)
+{
+ struct gralloc_drm_plane_t *plane = drm->planes;
+ unsigned int i;
+ for (i = 0; i < drm->plane_resources->count_planes;
+ i++, plane++) {
+ /* plane is not in use at all */
+ if (!plane->active && !plane->handle)
+ continue;
+
+ /* plane is active, safety check if it is supported */
+ if (!is_plane_supported(drm, plane))
+ ALOGE("%s: plane %d is not supported",
+ __func__, plane->drm_plane->plane_id);
+
+ /*
+ * Disable overlay if it is not active
+ * or if there is error during setplane
+ */
+ if (!plane->active)
+ plane->handle = 0;
+
+ if (gralloc_drm_bo_setplane(drm, plane))
+ plane->active = 0;
+ }
+}
+
+/*
+ * Interface for HWC, used to reserve a plane for a layer.
+ */
+int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
+ buffer_handle_t handle,
+ uint32_t id,
+ uint32_t dst_x,
+ uint32_t dst_y,
+ uint32_t dst_w,
+ uint32_t dst_h,
+ uint32_t src_x,
+ uint32_t src_y,
+ uint32_t src_w,
+ uint32_t src_h)
+{
+ unsigned int i, j;
+ struct gralloc_drm_handle_t *drm_handle =
+ gralloc_drm_handle(handle);
+ int plane_count = drm->plane_resources->count_planes;
+ struct gralloc_drm_plane_t *plane = drm->planes;
+
+ /* no supported planes for this handle */
+ if (!drm_handle->plane_mask) {
+ ALOGE("%s: buffer %p cannot be shown on a plane\n",
+ __func__, drm_handle);
+ return -EINVAL;
+ }
+
+ for (j = 0; j < plane_count; j++, plane++) {
+
+ /*
+ * handle may be suitable to be shown on a plane, in
+ * addition we need to check that this particular plane
+ * is supported by the current implementation
+ */
+ if (!is_plane_supported(drm, plane))
+ continue;
+
+ /* if plane is available and can support this buffer */
+ if (!plane->active &&
+ drm_handle->plane_mask &
+ (1U << plane->drm_plane->plane_id)) {
+
+ plane->dst_x = dst_x;
+ plane->dst_y = dst_y;
+ plane->dst_w = dst_w;
+ plane->dst_h = dst_h;
+ plane->src_x = src_x;
+ plane->src_y = src_y;
+ plane->src_w = src_w;
+ plane->src_h = src_h;
+ plane->handle = handle;
+ plane->id = id;
+ plane->active = 1;
+
+ return 0;
+ }
+ }
+
+ /* no free planes available */
+ return -EBUSY;
+}
+
+/*
+ * Interface for HWC, used to disable all the overlays. Plane id
+ * is also set to 0 as it should be mappable to a particular layer only
+ * if it has been reserved with 'reserve_plane'.
+ */
+void gralloc_drm_disable_planes(struct gralloc_drm_t *drm)
+{
+ struct gralloc_drm_plane_t *plane = drm->planes;
+ unsigned int i;
+
+ for (i = 0; i < drm->plane_resources->count_planes; i++, plane++) {
+ plane->active = 0;
+ plane->id = 0;
+ }
+}
+
+/*
+ * Interface for HWC, used to change handle of a reserved plane.
+ */
+int gralloc_drm_set_plane_handle(struct gralloc_drm_t *drm,
+ uint32_t id, buffer_handle_t handle)
+{
+ struct gralloc_drm_plane_t *plane = drm->planes;
+ unsigned i;
+
+ for (i = 0; i < drm->plane_resources->count_planes; i++, plane++)
+ if (plane->active && plane->id == id) {
+ plane->handle = handle;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Schedule a page flip.
+ */
+static int drm_kms_page_flip(struct gralloc_drm_t *drm,
+ struct gralloc_drm_bo_t *bo)
+{
+ int ret;
+
+ /* there is another flip pending */
+ while (drm->next_front) {
+ drm->waiting_flip = 1;
+ drmHandleEvent(drm->fd, &drm->evctx);
+ drm->waiting_flip = 0;
+ if (drm->next_front) {
+ /* record an error and break */
+ ALOGE("drmHandleEvent returned without flipping");
+ drm->current_front = drm->next_front;
+ drm->next_front = NULL;
+ }
+ }
+
+ if (!bo)
+ return 0;
+
+ pthread_mutex_lock(&drm->hdmi_mutex);
+ if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo) {
+
+ int dst_x1 = 0, dst_y1 = 0;
+
+ if (drm->hdmi.bo->handle->width > bo->handle->width)
+ dst_x1 = (drm->hdmi.bo->handle->width - bo->handle->width) / 2;
+ if (drm->hdmi.bo->handle->height > bo->handle->height)
+ dst_y1 = (drm->hdmi.bo->handle->height - bo->handle->height) / 2;
+
+ drm->drv->blit(drm->drv, drm->hdmi.bo, bo,
+ dst_x1, dst_y1,
+ dst_x1 + bo->handle->width,
+ dst_y1 + bo->handle->height,
+ 0, 0, bo->handle->width, bo->handle->height);
+
+ ret = drmModePageFlip(drm->fd, drm->hdmi.crtc_id, drm->hdmi.bo->fb_id, 0, NULL);
+ if (ret && errno != EBUSY)
+ ALOGE("failed to perform page flip for hdmi (%s) (crtc %d fb %d))",
+ strerror(errno), drm->hdmi.crtc_id, drm->hdmi.bo->fb_id);
+ }
+ pthread_mutex_unlock(&drm->hdmi_mutex);
+
+ /* set planes to be displayed */
+ gralloc_drm_set_planes(drm);
+
+ ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
+ DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
+ if (ret) {
+ ALOGE("failed to perform page flip for primary (%s) (crtc %d fb %d))",
+ strerror(errno), drm->primary.crtc_id, bo->fb_id);
+ /* try to set mode for next frame */
+ if (errno != EBUSY)
+ drm->first_post = 1;
+ }
+ else
+ drm->next_front = bo;
+
+ return ret;
+}
+
+/*
+ * Wait for the next post.
+ */
+static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
+{
+ unsigned int current, target;
+ drmVBlank vbl;
+ int ret;
+
+ if (drm->mode_quirk_vmwgfx)
+ return;
+
+ flip = !!flip;
+
+ memset(&vbl, 0, sizeof(vbl));
+ vbl.request.type = DRM_VBLANK_RELATIVE;
+ if (drm->vblank_secondary)
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ vbl.request.sequence = 0;
+
+ /* get the current vblank */
+ ret = drmWaitVBlank(drm->fd, &vbl);
+ if (ret) {
+ ALOGW("failed to get vblank");
+ return;
+ }
+
+ current = vbl.reply.sequence;
+ if (drm->first_post)
+ target = current;
+ else
+ target = drm->last_swap + drm->swap_interval - flip;
+
+ /* wait for vblank */
+ if (current < target || !flip) {
+ memset(&vbl, 0, sizeof(vbl));
+ vbl.request.type = DRM_VBLANK_ABSOLUTE;
+ if (drm->vblank_secondary)
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ if (!flip) {
+ vbl.request.type |= DRM_VBLANK_NEXTONMISS;
+ if (target < current)
+ target = current;
+ }
+
+ vbl.request.sequence = target;
+
+ ret = drmWaitVBlank(drm->fd, &vbl);
+ if (ret) {
+ ALOGW("failed to wait vblank");
+ return;
+ }
+ }
+
+ drm->last_swap = vbl.reply.sequence + flip;
+}
+
+/*
+ * Post a bo. This is not thread-safe.
+ */
+int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
+{
+ struct gralloc_drm_t *drm = bo->drm;
+ int ret;
+
+ if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
+ ALOGE("unable to post bo %p without fb", bo);
+ return -EINVAL;
+ }
+
+ /* TODO spawn a thread to avoid waiting and race */
+
+ if (drm->first_post) {
+ if (drm->swap_mode == DRM_SWAP_COPY) {
+ struct gralloc_drm_bo_t *dst;
+
+ dst = (drm->next_front) ?
+ drm->next_front :
+ drm->current_front;
+ drm->drv->blit(drm->drv, dst, bo, 0, 0,
+ bo->handle->width,
+ bo->handle->height,
+ 0, 0,
+ bo->handle->width,
+ bo->handle->height);
+ bo = dst;
+ }
+
+ ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
+ if (!ret) {
+ drm->first_post = 0;
+ drm->current_front = bo;
+ if (drm->next_front == bo)
+ drm->next_front = NULL;
+ }
+
+ pthread_mutex_lock(&drm->hdmi_mutex);
+ if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
+ drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
+ pthread_mutex_unlock(&drm->hdmi_mutex);
+
+ return ret;
+ }
+
+ switch (drm->swap_mode) {
+ case DRM_SWAP_FLIP:
+ if (drm->swap_interval > 1)
+ drm_kms_wait_for_post(drm, 1);
+ ret = drm_kms_page_flip(drm, bo);
+ if (drm->next_front) {
+ /*
+ * wait if the driver says so or the current front
+ * will be written by CPU
+ */
+ if (drm->mode_sync_flip ||
+ (drm->current_front->handle->usage &
+ GRALLOC_USAGE_SW_WRITE_MASK))
+ drm_kms_page_flip(drm, NULL);
+ }
+ break;
+ case DRM_SWAP_COPY:
+ drm_kms_wait_for_post(drm, 0);
+ drm->drv->blit(drm->drv, drm->current_front,
+ bo, 0, 0,
+ bo->handle->width,
+ bo->handle->height,
+ 0, 0,
+ bo->handle->width,
+ bo->handle->height);
+ if (drm->mode_quirk_vmwgfx)
+ ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
+ ret = 0;
+ break;
+ case DRM_SWAP_SETCRTC:
+ drm_kms_wait_for_post(drm, 0);
+ ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
+
+ pthread_mutex_lock(&drm->hdmi_mutex);
+ if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
+ drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
+ pthread_mutex_unlock(&drm->hdmi_mutex);
+
+ drm->current_front = bo;
+ break;
+ default:
+ /* no-op */
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static struct gralloc_drm_t *drm_singleton;
+
+static void on_signal(int sig)
+{
+ struct gralloc_drm_t *drm = drm_singleton;
+
+ /* wait the pending flip */
+ if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
+ /* there is race, but this function is hacky enough to ignore that */
+ if (drm_singleton->waiting_flip)
+ usleep(100 * 1000); /* 100ms */
+ else
+ drm_kms_page_flip(drm_singleton, NULL);
+ }
+
+ exit(-1);
+}
+
+static void drm_kms_init_features(struct gralloc_drm_t *drm)
+{
+ const char *swap_mode;
+
+ /* call to the driver here, after KMS has been initialized */
+ drm->drv->init_kms_features(drm->drv, drm);
+
+ if (drm->swap_mode == DRM_SWAP_FLIP) {
+ struct sigaction act;
+
+ memset(&drm->evctx, 0, sizeof(drm->evctx));
+ drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
+ drm->evctx.page_flip_handler = page_flip_handler;
+
+ /*
+ * XXX GPU tends to freeze if the program is terminiated with a
+ * flip pending. What is the right way to handle the
+ * situation?
+ */
+ sigemptyset(&act.sa_mask);
+ act.sa_handler = on_signal;
+ act.sa_flags = 0;
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+
+ drm_singleton = drm;
+ }
+ else if (drm->swap_mode == DRM_SWAP_COPY) {
+ struct gralloc_drm_bo_t *front;
+ int stride;
+
+ /* create the real front buffer */
+ front = gralloc_drm_bo_create(drm,
+ drm->primary.mode.hdisplay,
+ drm->primary.mode.vdisplay,
+ drm->primary.fb_format,
+ GRALLOC_USAGE_HW_FB);
+ if (front && gralloc_drm_bo_add_fb(front)) {
+ gralloc_drm_bo_decref(front);
+ front = NULL;
+ }
+
+ /* abuse next_front */
+ if (front)
+ drm->next_front = front;
+ else
+ drm->swap_mode = DRM_SWAP_SETCRTC;
+ }
+
+ switch (drm->swap_mode) {
+ case DRM_SWAP_FLIP:
+ swap_mode = "flip";
+ break;
+ case DRM_SWAP_COPY:
+ swap_mode = "copy";
+ break;
+ case DRM_SWAP_SETCRTC:
+ swap_mode = "set-crtc";
+ break;
+ default:
+ swap_mode = "no-op";
+ break;
+ }
+
+ ALOGD("will use %s for fb posting", swap_mode);
+}
+
+#define MARGIN_PERCENT 1.8 /* % of active vertical image*/
+#define CELL_GRAN 8.0 /* assumed character cell granularity*/
+#define MIN_PORCH 1 /* minimum front porch */
+#define V_SYNC_RQD 3 /* width of vsync in lines */
+#define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */
+#define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
+#define M 600.0 /* blanking formula gradient */
+#define C 40.0 /* blanking formula offset */
+#define K 128.0 /* blanking formula scaling factor */
+#define J 20.0 /* blanking formula scaling factor */
+/* C' and M' are part of the Blanking Duty Cycle computation */
+#define C_PRIME (((C - J) * K / 256.0) + J)
+#define M_PRIME (K / 256.0 * M)
+
+static drmModeModeInfoPtr generate_mode(int h_pixels, int v_lines, float freq)
+{
+ float h_pixels_rnd;
+ float v_lines_rnd;
+ float v_field_rate_rqd;
+ float top_margin;
+ float bottom_margin;
+ float interlace;
+ float h_period_est;
+ float vsync_plus_bp;
+ float v_back_porch;
+ float total_v_lines;
+ float v_field_rate_est;
+ float h_period;
+ float v_field_rate;
+ float v_frame_rate;
+ float left_margin;
+ float right_margin;
+ float total_active_pixels;
+ float ideal_duty_cycle;
+ float h_blank;
+ float total_pixels;
+ float pixel_freq;
+ float h_freq;
+
+ float h_sync;
+ float h_front_porch;
+ float v_odd_front_porch_lines;
+ int interlaced = 0;
+ int margins = 0;
+
+ drmModeModeInfoPtr m = malloc(sizeof(drmModeModeInfo));
+
+ h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN;
+ v_lines_rnd = interlaced ? rint((float) v_lines) / 2.0 : rint((float) v_lines);
+ v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq);
+ top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
+ bottom_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
+ interlace = interlaced ? 0.5 : 0.0;
+ h_period_est = (((1.0 / v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP / 1000000.0)) / (v_lines_rnd + (2 * top_margin) + MIN_PORCH + interlace) * 1000000.0);
+ vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP / h_period_est);
+ v_back_porch = vsync_plus_bp - V_SYNC_RQD;
+ total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + interlace + MIN_PORCH;
+ v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
+ h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
+ v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0;
+ v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate;
+ left_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
+ right_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
+ total_active_pixels = h_pixels_rnd + left_margin + right_margin;
+ ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
+ h_blank = rint(total_active_pixels * ideal_duty_cycle / (100.0 - ideal_duty_cycle) / (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
+ total_pixels = total_active_pixels + h_blank;
+ pixel_freq = total_pixels / h_period;
+ h_freq = 1000.0 / h_period;
+ h_sync = rint(H_SYNC_PERCENT / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
+ h_front_porch = (h_blank / 2.0) - h_sync;
+ v_odd_front_porch_lines = MIN_PORCH + interlace;
+
+ m->clock = ceil(pixel_freq) * 1000;
+ m->hdisplay = (int) (h_pixels_rnd);
+ m->hsync_start = (int) (h_pixels_rnd + h_front_porch);
+ m->hsync_end = (int) (h_pixels_rnd + h_front_porch + h_sync);
+ m->htotal = (int) (total_pixels);
+ m->hskew = 0;
+ m->vdisplay = (int) (v_lines_rnd);
+ m->vsync_start = (int) (v_lines_rnd + v_odd_front_porch_lines);
+ m->vsync_end = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD);
+ m->vtotal = (int) (total_v_lines);
+ m->vscan = 0;
+ m->vrefresh = freq;
+ m->flags = 10;
+ m->type = 64;
+
+ return (m);
+}
+
+static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
+{
+ char value[PROPERTY_VALUE_MAX];
+ drmModeModeInfoPtr mode;
+ int dist, i;
+ int xres = 0, yres = 0, rate = 0;
+ int forcemode = 0;
+
+ if (property_get("debug.drm.mode", value, NULL)) {
+ char *p = value, *end;
+
+ /* parse <xres>x<yres>[@<bpp>] */
+ if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
+ *bpp = 0;
+ if (sscanf(value, "%dx%d", &xres, &yres) != 2)
+ xres = yres = 0;
+ }
+
+ if ((xres && yres) || *bpp) {
+ ALOGI("will find the closest match for %dx%d@%d",
+ xres, yres, *bpp);
+ }
+ } else if (property_get("debug.drm.mode.force", value, NULL)) {
+ char *p = value, *end;
+ *bpp = 0;
+
+ /* parse <xres>x<yres>[@<refreshrate>] */
+ if (sscanf(value, "%dx%d@%d", &xres, &yres, &rate) != 3) {
+ rate = 60;
+ if (sscanf(value, "%dx%d", &xres, &yres) != 2)
+ xres = yres = 0;
+ }
+
+ if (xres && yres && rate) {
+ ALOGI("will use %dx%d@%dHz", xres, yres, rate);
+ forcemode = 1;
+ }
+ } else {
+ *bpp = 0;
+ }
+
+ dist = INT_MAX;
+
+ if (forcemode)
+ mode = generate_mode(xres, yres, rate);
+ else {
+ mode = NULL;
+ for (i = 0; i < connector->count_modes; i++) {
+ drmModeModeInfoPtr m = &connector->modes[i];
+ int tmp;
+
+ if (xres && yres) {
+ tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
+ (m->vdisplay - yres) * (m->vdisplay - yres);
+ }
+ else {
+ /* use the first preferred mode */
+ tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
+ }
+
+ if (tmp < dist) {
+ mode = m;
+ dist = tmp;
+ if (!dist)
+ break;
+ }
+ }
+ }
+
+ /* fallback to the first mode */
+ if (!mode)
+ mode = &connector->modes[0];
+
+ ALOGI("Established mode:");
+ ALOGI("clock: %d, hdisplay: %d, hsync_start: %d, hsync_end: %d, htotal: %d, hskew: %d", mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->hskew);
+ ALOGI("vdisplay: %d, vsync_start: %d, vsync_end: %d, vtotal: %d, vscan: %d, vrefresh: %d", mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, mode->vscan, mode->vrefresh);
+ ALOGI("flags: %d, type: %d, name %s", mode->flags, mode->type, mode->name);
+
+ *bpp /= 8;
+
+ return mode;
+}
+
+/*
+ * Initialize KMS with a connector.
+ */
+static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
+ struct gralloc_drm_output *output, drmModeConnectorPtr connector)
+{
+ drmModeEncoderPtr encoder;
+ drmModeModeInfoPtr mode;
+ static int used_crtcs = 0;
+ int bpp, i;
+
+ if (!connector->count_modes)
+ return -EINVAL;
+
+ encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
+ if (!encoder)
+ return -EINVAL;
+
+ /* find first possible crtc which is not used yet */
+ for (i = 0; i < drm->resources->count_crtcs; i++) {
+ if (encoder->possible_crtcs & (1 << i) &&
+ (used_crtcs & (1 << i)) != (1 << i))
+ break;
+ }
+
+ used_crtcs |= (1 << i);
+
+ drmModeFreeEncoder(encoder);
+ if (i == drm->resources->count_crtcs)
+ return -EINVAL;
+
+ output->bo = NULL;
+ output->crtc_id = drm->resources->crtcs[i];
+ output->connector_id = connector->connector_id;
+ output->pipe = i;
+
+ /* print connector info */
+ if (connector->count_modes > 1) {
+ ALOGI("there are %d modes on connector 0x%x, type %d",
+ connector->count_modes,
+ connector->connector_id,
+ connector->connector_type);
+ for (i = 0; i < connector->count_modes; i++)
+ ALOGI(" %s", connector->modes[i].name);
+ }
+ else {
+ ALOGI("there is one mode on connector 0x%d: %s",
+ connector->connector_id,
+ connector->modes[0].name);
+ }
+
+ mode = find_mode(connector, &bpp);
+
+ ALOGI("the best mode is %s", mode->name);
+
+ output->mode = *mode;
+ switch (bpp) {
+ case 2:
+ output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
+ break;
+ case 4:
+ default:
+ output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
+ break;
+ }
+
+ if (connector->mmWidth && connector->mmHeight) {
+ output->xdpi = (output->mode.hdisplay * 25.4 / connector->mmWidth);
+ output->ydpi = (output->mode.vdisplay * 25.4 / connector->mmHeight);
+ }
+ else {
+ output->xdpi = 75;
+ output->ydpi = 75;
+ }
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+ drm->clip.x1 = 0;
+ drm->clip.y1 = 0;
+ drm->clip.x2 = output->mode.hdisplay;
+ drm->clip.y2 = output->mode.vdisplay;
+#endif
+
+ return 0;
+}
+
+
+/*
+ * Fetch a connector of particular type
+ */
+static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
+ uint32_t type)
+{
+ int i;
+
+ if (!drm->resources)
+ return NULL;
+
+ for (i = 0; i < drm->resources->count_connectors; i++) {
+ drmModeConnectorPtr connector =
+ connector = drmModeGetConnector(drm->fd,
+ drm->resources->connectors[i]);
+ if (connector) {
+ if (connector->connector_type == type &&
+ connector->connection == DRM_MODE_CONNECTED)
+ return connector;
+ drmModeFreeConnector(connector);
+ }
+ }
+ return NULL;
+}
+
+
+/*
+ * Initializes hdmi output with a connector and allocates
+ * a private framebuffer for it. This is called on startup if
+ * hdmi cable is connected and also on hotplug events.
+ */
+static void init_hdmi_output(struct gralloc_drm_t *drm,
+ drmModeConnectorPtr connector)
+{
+ drm_kms_init_with_connector(drm, &drm->hdmi, connector);
+
+ ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
+ __func__, drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay);
+
+ drm->hdmi.bo = gralloc_drm_bo_create(drm,
+ drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay,
+ drm->hdmi.fb_format,
+ GRALLOC_USAGE_SW_WRITE_OFTEN|GRALLOC_USAGE_HW_RENDER);
+
+ gralloc_drm_bo_add_fb(drm->hdmi.bo);
+
+ drm->hdmi_mode = HDMI_CLONED;
+ drm->hdmi.active = 1;
+}
+
+
+/*
+ * Thread that listens to uevents and checks if hdmi state changes
+ */
+static void *hdmi_observer(void *data)
+{
+ static char uevent_desc[4096];
+ drmModeConnectorPtr hdmi;
+ struct gralloc_drm_t *drm =
+ (struct gralloc_drm_t *) data;
+
+ uevent_init();
+
+ memset(uevent_desc, 0, sizeof(uevent_desc));
+
+ while(1) {
+
+ /* this polls */
+ int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
+
+ if(len && strstr(uevent_desc, "devices/virtual/switch/hdmi")) {
+
+ /* check what changed */
+ const char *prop = uevent_desc + strlen(uevent_desc) + 1;
+
+ while (*prop) {
+
+ const char *state = strstr(prop, "SWITCH_STATE=");
+ if (state) {
+ unsigned int value = 0;
+ state += strlen("SWITCH_STATE=");
+ value = atoi(state);
+
+ pthread_mutex_lock(&drm->hdmi_mutex);
+
+ if (value) {
+ hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
+ if (hdmi) {
+
+ ALOGD("init hdmi on hotplug event");
+ init_hdmi_output(drm, hdmi);
+
+ /* will trigger modeset */
+ drm->first_post = 1;
+
+ drmModeFreeConnector(hdmi);
+
+ pthread_mutex_unlock(&drm->hdmi_mutex);
+ }
+ break;
+ } else {
+ drm->hdmi.active = 0;
+
+ ALOGD("destroy hdmi private buffer");
+ gralloc_drm_bo_decref(drm->hdmi.bo);
+ drm->hdmi.bo = NULL;
+
+ pthread_mutex_unlock(&drm->hdmi_mutex);
+ break;
+ }
+
+ pthread_mutex_unlock(&drm->hdmi_mutex);
+ }
+
+ /* next property/value pair */
+ prop += strlen(prop) + 1;
+ if (prop - uevent_desc >= len)
+ break;
+ }
+ }
+ }
+
+ pthread_exit(NULL);
+ return 0;
+}
+
+
+/*
+ * Initialize KMS.
+ */
+int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
+{
+ drmModeConnectorPtr lvds, hdmi;
+ int i, ret;
+
+ if (drm->resources)
+ return 0;
+
+ drm->resources = drmModeGetResources(drm->fd);
+ if (!drm->resources) {
+ ALOGE("failed to get modeset resources");
+ return -EINVAL;
+ }
+
+ drm->plane_resources = drmModeGetPlaneResources(drm->fd);
+ if (!drm->plane_resources) {
+ ALOGD("no planes found from drm resources");
+ } else {
+ ALOGD("supported drm planes and formats");
+ /* fill a helper structure for hwcomposer */
+ drm->planes = calloc(drm->plane_resources->count_planes,
+ sizeof(struct gralloc_drm_plane_t));
+
+ for (i = 0; i < drm->plane_resources->count_planes; i++) {
+
+ unsigned int j;
+
+ drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
+ drm->plane_resources->planes[i]);
+
+ ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
+ for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
+ ALOGD(" format %c%c%c%c",
+ (drm->planes[i].drm_plane->formats[j]),
+ (drm->planes[i].drm_plane->formats[j])>>8,
+ (drm->planes[i].drm_plane->formats[j])>>16,
+ (drm->planes[i].drm_plane->formats[j])>>24);
+ }
+ }
+
+ /* find the crtc/connector/mode to use */
+ lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
+ if (lvds) {
+ drm_kms_init_with_connector(drm, &drm->primary, lvds);
+ drmModeFreeConnector(lvds);
+ drm->primary.active = 1;
+ }
+
+ /* if still no connector, find first connected connector and try it */
+ if (!drm->primary.active) {
+
+ for (i = 0; i < drm->resources->count_connectors; i++) {
+ drmModeConnectorPtr connector;
+
+ connector = drmModeGetConnector(drm->fd,
+ drm->resources->connectors[i]);
+ if (connector) {
+ if (connector->connection == DRM_MODE_CONNECTED) {
+ if (!drm_kms_init_with_connector(drm,
+ &drm->primary, connector))
+ break;
+ }
+
+ drmModeFreeConnector(connector);
+ }
+ }
+ if (i == drm->resources->count_connectors) {
+ ALOGE("failed to find a valid crtc/connector/mode combination");
+ drmModeFreeResources(drm->resources);
+ drm->resources = NULL;
+
+ return -EINVAL;
+ }
+ }
+
+
+ /* check if hdmi is connected already */
+ hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
+ if (hdmi) {
+
+ if (hdmi->connector_id == drm->primary.connector_id) {
+ /* special case: our primary connector is hdmi */
+ ALOGD("hdmi is the primary connector");
+ goto skip_hdmi_modes;
+ }
+
+ ALOGD("init hdmi on startup");
+ init_hdmi_output(drm, hdmi);
+
+ drmModeFreeConnector(hdmi);
+ }
+
+goto skip_hdmi_modes;
+ /* launch hdmi observer thread */
+ pthread_mutex_init(&drm->hdmi_mutex, NULL);
+ pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
+
+skip_hdmi_modes:
+
+ drm_kms_init_features(drm);
+ drm->first_post = 1;
+
+ return 0;
+}
+
+void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
+{
+ switch (drm->swap_mode) {
+ case DRM_SWAP_FLIP:
+ drm_kms_page_flip(drm, NULL);
+ break;
+ case DRM_SWAP_COPY:
+ {
+ struct gralloc_drm_bo_t **bo = (drm->current_front) ?
+ &drm->current_front : &drm->next_front;
+
+ if (*bo)
+ gralloc_drm_bo_decref(*bo);
+ *bo = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* restore crtc? */
+
+ if (drm->resources) {
+ drmModeFreeResources(drm->resources);
+ drm->resources = NULL;
+ }
+
+ if (drm->planes) {
+ unsigned int i;
+ for (i = 0; i < drm->plane_resources->count_planes; i++)
+ drmModeFreePlane(drm->planes[i].drm_plane);
+ free(drm->planes);
+ drm->planes = NULL;
+ }
+
+ if (drm->plane_resources) {
+ drmModeFreePlaneResources(drm->plane_resources);
+ drm->plane_resources = NULL;
+ }
+
+ /* destroy private buffer of hdmi output */
+ if (drm->hdmi.bo)
+ gralloc_drm_bo_decref(drm->hdmi.bo);
+
+ drm_singleton = NULL;
+}
+
+int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
+{
+ return (drm->resources != NULL);
+}
+
+/*
+ * Initialize a framebuffer device with KMS info.
+ */
+void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
+ struct framebuffer_device_t *fb)
+{
+ *((uint32_t *) &fb->flags) = 0x0;
+ *((uint32_t *) &fb->width) = drm->primary.mode.hdisplay;
+ *((uint32_t *) &fb->height) = drm->primary.mode.vdisplay;
+ *((int *) &fb->stride) = drm->primary.mode.hdisplay;
+ *((float *) &fb->fps) = drm->primary.mode.vrefresh;
+
+ *((int *) &fb->format) = drm->primary.fb_format;
+ *((float *) &fb->xdpi) = drm->primary.xdpi;
+ *((float *) &fb->ydpi) = drm->primary.ydpi;
+ *((int *) &fb->minSwapInterval) = drm->swap_interval;
+ *((int *) &fb->maxSwapInterval) = drm->swap_interval;
+}
+
+/*
+ * Return true if fb posting is pipelined.
+ */
+int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
+{
+ return (drm->swap_mode != DRM_SWAP_SETCRTC);
+}
diff --git a/src/drm_gralloc/gralloc_drm_priv.h b/src/drm_gralloc/gralloc_drm_priv.h
new file mode 100644
index 0000000..1a36cc1
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm_priv.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _GRALLOC_DRM_PRIV_H_
+#define _GRALLOC_DRM_PRIV_H_
+
+#include <pthread.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "gralloc_drm_handle.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* how a bo is posted */
+enum drm_swap_mode {
+ DRM_SWAP_NOOP,
+ DRM_SWAP_FLIP,
+ DRM_SWAP_COPY,
+ DRM_SWAP_SETCRTC,
+};
+
+enum hdmi_output_mode {
+ HDMI_CLONED,
+ HDMI_EXTENDED,
+};
+
+struct gralloc_drm_plane_t {
+ drmModePlane *drm_plane;
+
+ /* plane has been set to display a layer */
+ uint32_t active;
+
+ /* handle to display */
+ buffer_handle_t handle;
+
+ /* identifier set by hwc */
+ uint32_t id;
+
+ /* position, crop and scale */
+ uint32_t src_x;
+ uint32_t src_y;
+ uint32_t src_w;
+ uint32_t src_h;
+ uint32_t dst_x;
+ uint32_t dst_y;
+ uint32_t dst_w;
+ uint32_t dst_h;
+
+ /* previous buffer, for refcounting */
+ struct gralloc_drm_bo_t *prev;
+};
+
+struct gralloc_drm_output
+{
+ uint32_t crtc_id;
+ uint32_t connector_id;
+ uint32_t pipe;
+ drmModeModeInfo mode;
+ int xdpi, ydpi;
+ int fb_format;
+ int bpp;
+ uint32_t active;
+
+ /* 'private fb' for this output */
+ struct gralloc_drm_bo_t *bo;
+};
+
+struct gralloc_drm_t {
+ /* initialized by gralloc_drm_create */
+ int fd;
+ struct gralloc_drm_drv_t *drv;
+
+ /* initialized by gralloc_drm_init_kms */
+ drmModeResPtr resources;
+ struct gralloc_drm_output primary;
+ struct gralloc_drm_output hdmi;
+ enum hdmi_output_mode hdmi_mode;
+
+ /* hdmi hotplug */
+ pthread_mutex_t hdmi_mutex;
+ pthread_t hdmi_hotplug_thread;
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+ drmModeClip clip;
+#endif
+
+ /* initialized by drv->init_kms_features */
+ enum drm_swap_mode swap_mode;
+ int swap_interval;
+ int mode_quirk_vmwgfx;
+ int mode_sync_flip; /* page flip should block */
+ int vblank_secondary;
+
+ drmEventContext evctx;
+
+ int first_post;
+ struct gralloc_drm_bo_t *current_front, *next_front;
+ int waiting_flip;
+ unsigned int last_swap;
+
+ /* plane support */
+ drmModePlaneResPtr plane_resources;
+ struct gralloc_drm_plane_t *planes;
+};
+
+struct drm_module_t {
+ gralloc_module_t base;
+
+ /* HWC plane API */
+ int (*hwc_reserve_plane) (struct gralloc_drm_t *mod,
+ buffer_handle_t handle, uint32_t id,
+ uint32_t dst_x, uint32_t dst_y, uint32_t dst_w, uint32_t dst_h,
+ uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h);
+ void (*hwc_disable_planes) (struct gralloc_drm_t *mod);
+ int (*hwc_set_plane_handle) (struct gralloc_drm_t *mod,
+ uint32_t id, buffer_handle_t handle);
+
+ pthread_mutex_t mutex;
+ struct gralloc_drm_t *drm;
+};
+
+struct gralloc_drm_drv_t {
+ /* destroy the driver */
+ void (*destroy)(struct gralloc_drm_drv_t *drv);
+
+ /* initialize KMS features */
+ void (*init_kms_features)(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_t *drm);
+
+ /* allocate or import a bo */
+ struct gralloc_drm_bo_t *(*alloc)(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_handle_t *handle);
+
+ /* free a bo */
+ void (*free)(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo);
+
+ /* map a bo for CPU access */
+ int (*map)(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo,
+ int x, int y, int w, int h, int enable_write, void **addr);
+
+ /* unmap a bo */
+ void (*unmap)(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo);
+
+ /* blit between two bo's, used for DRM_SWAP_COPY and general blitting */
+ void (*blit)(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *dst,
+ struct gralloc_drm_bo_t *src,
+ uint16_t dst_x1, uint16_t dst_y1,
+ uint16_t dst_x2, uint16_t dst_y2,
+ uint16_t src_x1, uint16_t src_y1,
+ uint16_t src_x2, uint16_t src_y2);
+
+ /* query component offsets, strides and handles for a format */
+ void (*resolve_format)(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo,
+ uint32_t *pitches, uint32_t *offsets, uint32_t *handles);
+};
+
+struct gralloc_drm_bo_t {
+ struct gralloc_drm_t *drm;
+ struct gralloc_drm_handle_t *handle;
+
+ int imported; /* the handle is from a remote proces when true */
+ int fb_handle; /* the GEM handle of the bo */
+ int fb_id; /* the fb id */
+
+ int lock_count;
+ int locked_for;
+
+ unsigned int refcount;
+};
+
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_pipe(int fd, const char *name);
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd);
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_radeon(int fd);
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_nouveau(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _GRALLOC_DRM_PRIV_H_ */