summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChia-I Wu <olvaffe@gmail.com>2011-06-12 16:21:30 +0800
committerChia-I Wu <olvaffe@gmail.com>2011-06-12 16:21:30 +0800
commit2ec32d4f949f04d0006fff50065c904626c2e581 (patch)
tree7971ee3431e97f7fe7c0bc6ae17948866e10de1e
initial commit
-rw-r--r--Android.mk77
-rw-r--r--dri/intel_chipset.h172
-rw-r--r--gralloc.c364
-rw-r--r--gralloc_drm.c304
-rw-r--r--gralloc_drm.h84
-rw-r--r--gralloc_drm_handle.h63
-rw-r--r--gralloc_drm_intel.c585
-rw-r--r--gralloc_drm_kms.c499
-rw-r--r--gralloc_drm_priv.h115
-rw-r--r--gralloc_drm_radeon.c366
10 files changed, 2629 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..8aec666
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,77 @@
+# Copyright (C) 2010 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.
+
+# Android.mk for drm_gralloc
+
+ifeq ($(strip $(BOARD_USES_DRM)),true)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+DRM_USES_INTEL := $(findstring true, \
+ $(BOARD_USES_I915C) \
+ $(BOARD_USES_I965C) \
+ $(BOARD_USES_I915G) \
+ $(BOARD_USES_I965G))
+
+DRM_USES_RADEON := $(findstring true, \
+ $(BOARD_USES_R300G) \
+ $(BOARD_USES_R600G))
+
+LOCAL_SRC_FILES := \
+ gralloc.c \
+ gralloc_drm.c \
+ gralloc_drm_kms.c
+
+LOCAL_C_INCLUDES := \
+ external/drm \
+ external/drm/include/drm
+
+LOCAL_SHARED_LIBRARIES := \
+ libdrm \
+ liblog \
+ libcutils \
+
+# for glFlush/glFinish
+LOCAL_SHARED_LIBRARIES += \
+ libGLESv1_CM
+
+ifeq ($(strip $(DRM_USES_INTEL)),true)
+LOCAL_SRC_FILES += gralloc_drm_intel.c
+LOCAL_C_INCLUDES += external/drm/intel
+LOCAL_CFLAGS += -DENABLE_INTEL
+LOCAL_SHARED_LIBRARIES += libdrm_intel
+endif # DRM_USES_INTEL
+
+ifeq ($(strip $(DRM_USES_RADEON)),true)
+LOCAL_SRC_FILES += gralloc_drm_radeon.c
+LOCAL_C_INCLUDES += external/drm/radeon
+LOCAL_CFLAGS += -DENABLE_RADEON
+LOCAL_SHARED_LIBRARIES += libdrm_radeon
+endif # DRM_USES_RADEON
+
+LOCAL_MODULE := gralloc.$(TARGET_PRODUCT)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif # BOARD_USES_DRM
diff --git a/dri/intel_chipset.h b/dri/intel_chipset.h
new file mode 100644
index 0000000..2e9fb2d
--- /dev/null
+++ b/dri/intel_chipset.h
@@ -0,0 +1,172 @@
+ /*
+ * Copyright © 2007 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#define PCI_CHIP_I810 0x7121
+#define PCI_CHIP_I810_DC100 0x7123
+#define PCI_CHIP_I810_E 0x7125
+#define PCI_CHIP_I815 0x1132
+
+#define PCI_CHIP_I830_M 0x3577
+#define PCI_CHIP_845_G 0x2562
+#define PCI_CHIP_I855_GM 0x3582
+#define PCI_CHIP_I865_G 0x2572
+
+#define PCI_CHIP_I915_G 0x2582
+#define PCI_CHIP_E7221_G 0x258A
+#define PCI_CHIP_I915_GM 0x2592
+#define PCI_CHIP_I945_G 0x2772
+#define PCI_CHIP_I945_GM 0x27A2
+#define PCI_CHIP_I945_GME 0x27AE
+
+#define PCI_CHIP_Q35_G 0x29B2
+#define PCI_CHIP_G33_G 0x29C2
+#define PCI_CHIP_Q33_G 0x29D2
+
+#define PCI_CHIP_IGD_GM 0xA011
+#define PCI_CHIP_IGD_G 0xA001
+
+#define IS_IGDGM(devid) (devid == PCI_CHIP_IGD_GM)
+#define IS_IGDG(devid) (devid == PCI_CHIP_IGD_G)
+#define IS_IGD(devid) (IS_IGDG(devid) || IS_IGDGM(devid))
+
+#define PCI_CHIP_I965_G 0x29A2
+#define PCI_CHIP_I965_Q 0x2992
+#define PCI_CHIP_I965_G_1 0x2982
+#define PCI_CHIP_I946_GZ 0x2972
+#define PCI_CHIP_I965_GM 0x2A02
+#define PCI_CHIP_I965_GME 0x2A12
+
+#define PCI_CHIP_GM45_GM 0x2A42
+
+#define PCI_CHIP_IGD_E_G 0x2E02
+#define PCI_CHIP_Q45_G 0x2E12
+#define PCI_CHIP_G45_G 0x2E22
+#define PCI_CHIP_G41_G 0x2E32
+#define PCI_CHIP_B43_G 0x2E42
+#define PCI_CHIP_B43_G1 0x2E92
+
+#define PCI_CHIP_ILD_G 0x0042
+#define PCI_CHIP_ILM_G 0x0046
+
+#define PCI_CHIP_SANDYBRIDGE_GT1 0x0102 /* Desktop */
+#define PCI_CHIP_SANDYBRIDGE_GT2 0x0112
+#define PCI_CHIP_SANDYBRIDGE_GT2_PLUS 0x0122
+#define PCI_CHIP_SANDYBRIDGE_M_GT1 0x0106 /* Mobile */
+#define PCI_CHIP_SANDYBRIDGE_M_GT2 0x0116
+#define PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS 0x0126
+#define PCI_CHIP_SANDYBRIDGE_S 0x010A /* Server */
+
+#define PCI_CHIP_IVYBRIDGE_GT1 0x0152 /* Desktop */
+#define PCI_CHIP_IVYBRIDGE_GT2 0x0162
+#define PCI_CHIP_IVYBRIDGE_M_GT1 0x0156 /* Mobile */
+#define PCI_CHIP_IVYBRIDGE_M_GT2 0x0166
+#define PCI_CHIP_IVYBRIDGE_S_GT1 0x015a /* Server */
+
+#define IS_MOBILE(devid) (devid == PCI_CHIP_I855_GM || \
+ devid == PCI_CHIP_I915_GM || \
+ devid == PCI_CHIP_I945_GM || \
+ devid == PCI_CHIP_I945_GME || \
+ devid == PCI_CHIP_I965_GM || \
+ devid == PCI_CHIP_I965_GME || \
+ devid == PCI_CHIP_GM45_GM || \
+ IS_IGD(devid) || \
+ devid == PCI_CHIP_ILM_G)
+
+#define IS_G45(devid) (devid == PCI_CHIP_IGD_E_G || \
+ devid == PCI_CHIP_Q45_G || \
+ devid == PCI_CHIP_G45_G || \
+ devid == PCI_CHIP_G41_G || \
+ devid == PCI_CHIP_B43_G || \
+ devid == PCI_CHIP_B43_G1)
+#define IS_GM45(devid) (devid == PCI_CHIP_GM45_GM)
+#define IS_G4X(devid) (IS_G45(devid) || IS_GM45(devid))
+
+#define IS_ILD(devid) (devid == PCI_CHIP_ILD_G)
+#define IS_ILM(devid) (devid == PCI_CHIP_ILM_G)
+#define IS_GEN5(devid) (IS_ILD(devid) || IS_ILM(devid))
+
+#define IS_915(devid) (devid == PCI_CHIP_I915_G || \
+ devid == PCI_CHIP_E7221_G || \
+ devid == PCI_CHIP_I915_GM)
+
+#define IS_945(devid) (devid == PCI_CHIP_I945_G || \
+ devid == PCI_CHIP_I945_GM || \
+ devid == PCI_CHIP_I945_GME || \
+ devid == PCI_CHIP_G33_G || \
+ devid == PCI_CHIP_Q33_G || \
+ devid == PCI_CHIP_Q35_G || IS_IGD(devid))
+
+#define IS_GEN4(devid) (devid == PCI_CHIP_I965_G || \
+ devid == PCI_CHIP_I965_Q || \
+ devid == PCI_CHIP_I965_G_1 || \
+ devid == PCI_CHIP_I965_GM || \
+ devid == PCI_CHIP_I965_GME || \
+ devid == PCI_CHIP_I946_GZ || \
+ IS_G4X(devid))
+
+/* Compat macro for intel_decode.c */
+#define IS_IRONLAKE(devid) IS_GEN5(devid)
+
+#define IS_SNB_GT1(devid) (devid == PCI_CHIP_SANDYBRIDGE_GT1 || \
+ devid == PCI_CHIP_SANDYBRIDGE_M_GT1 || \
+ devid == PCI_CHIP_SANDYBRIDGE_S)
+
+#define IS_SNB_GT2(devid) (devid == PCI_CHIP_SANDYBRIDGE_GT2 || \
+ devid == PCI_CHIP_SANDYBRIDGE_GT2_PLUS || \
+ devid == PCI_CHIP_SANDYBRIDGE_M_GT2 || \
+ devid == PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS)
+
+#define IS_GEN6(devid) (IS_SNB_GT1(devid) || IS_SNB_GT2(devid))
+
+#define IS_IVB_GT1(devid) (devid == PCI_CHIP_IVYBRIDGE_GT1 || \
+ devid == PCI_CHIP_IVYBRIDGE_M_GT1 || \
+ devid == PCI_CHIP_IVYBRIDGE_S_GT1)
+
+#define IS_IVB_GT2(devid) (devid == PCI_CHIP_IVYBRIDGE_GT2 || \
+ devid == PCI_CHIP_IVYBRIDGE_M_GT2)
+
+#define IS_IVYBRIDGE(devid) (IS_IVB_GT1(devid) || IS_IVB_GT2(devid))
+
+#define IS_GEN7(devid) IS_IVYBRIDGE(devid)
+
+#define IS_965(devid) (IS_GEN4(devid) || \
+ IS_G4X(devid) || \
+ IS_GEN5(devid) || \
+ IS_GEN6(devid) || \
+ IS_GEN7(devid))
+
+#define IS_9XX(devid) (IS_915(devid) || \
+ IS_945(devid) || \
+ IS_965(devid))
+
+#define IS_GEN3(devid) (IS_915(devid) || \
+ IS_945(devid))
+
+#define IS_GEN2(devid) (devid == PCI_CHIP_I830_M || \
+ devid == PCI_CHIP_845_G || \
+ devid == PCI_CHIP_I855_GM || \
+ devid == PCI_CHIP_I865_G)
diff --git a/gralloc.c b/gralloc.c
new file mode 100644
index 0000000..850a39e
--- /dev/null
+++ b/gralloc.c
@@ -0,0 +1,364 @@
+/*
+ * 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_handle.h"
+
+struct drm_module_t {
+ gralloc_module_t base;
+
+ pthread_mutex_t mutex;
+ struct gralloc_drm_t *drm;
+};
+
+/*
+ * 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)
+{
+ return (gralloc_drm_handle(handle)) ? 0 : -EINVAL;
+}
+
+static int drm_mod_unregister_buffer(const gralloc_module_t *mod,
+ buffer_handle_t handle)
+{
+ return (gralloc_drm_handle(handle)) ? 0 : -EINVAL;
+}
+
+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 drm_module_t *dmod = (struct drm_module_t *) mod;
+ struct gralloc_drm_bo_t *bo;
+ int err;
+
+ err = drm_init(dmod, 0);
+ if (err)
+ return err;
+
+ bo = gralloc_drm_bo_validate(dmod->drm, handle);
+ if (!bo)
+ return -EINVAL;
+
+ return gralloc_drm_bo_map(bo, x, y, w, h, 1, 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_validate(dmod->drm, handle);
+ if (!bo)
+ return -EINVAL;
+
+ gralloc_drm_bo_unmap(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_validate(dmod->drm, handle);
+ if (!bo)
+ return -EINVAL;
+
+ if (gralloc_drm_bo_need_fb(bo))
+ gralloc_drm_bo_rm_fb(bo);
+ gralloc_drm_bo_destroy(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) {
+ LOGE("failed to add fb");
+ gralloc_drm_bo_destroy(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_validate(dmod->drm, 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;
+
+ LOGI("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
+ },
+ .mutex = PTHREAD_MUTEX_INITIALIZER,
+ .drm = NULL
+};
diff --git a/gralloc_drm.c b/gralloc_drm.c
new file mode 100644
index 0000000..63e504b
--- /dev/null
+++ b/gralloc_drm.c
@@ -0,0 +1,304 @@
+/*
+ * 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) {
+ LOGE("invalid DRM fd");
+ return NULL;
+ }
+
+ if (version->name) {
+#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_VMWGFX
+ if (!drv && !strcmp(version->name, "vmwgfx"))
+ drv = gralloc_drm_drv_create_for_vmwgfx(fd);
+#endif
+ }
+
+ if (!drv) {
+ LOGE("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) {
+ LOGE("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)
+{
+ LOGD("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);
+}
+
+/*
+ * 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;
+
+ 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;
+
+ bo = drm->drv->alloc(drm->drv, handle);
+ if (!bo) {
+ free(handle);
+ return NULL;
+ }
+
+ bo->drm = drm;
+ bo->imported = 0;
+ bo->handle = handle;
+
+ handle->data_owner = gralloc_drm_get_pid();
+ handle->data = (int) bo;
+
+ return bo;
+}
+
+/*
+ * Validate a buffer handle and return the associated bo.
+ */
+struct gralloc_drm_bo_t *gralloc_drm_bo_validate(struct gralloc_drm_t *drm,
+ buffer_handle_t _handle)
+{
+ struct gralloc_drm_handle_t *handle = gralloc_drm_handle(_handle);
+
+ /* the buffer handle is passed to a new process */
+ if (handle && unlikely(handle->data_owner != gralloc_drm_pid)) {
+ struct gralloc_drm_bo_t *bo;
+
+ /* create the struct gralloc_drm_bo_t locally */
+ bo = drm->drv->alloc(drm->drv, handle);
+ if (bo) {
+ bo->drm = drm;
+ bo->imported = 1;
+ bo->handle = handle;
+ }
+
+ handle->data_owner = gralloc_drm_get_pid();
+ handle->data = (int) bo;
+ }
+
+ return (struct gralloc_drm_bo_t *) handle->data;
+}
+
+/*
+ * Destroy a bo.
+ */
+void gralloc_drm_bo_destroy(struct gralloc_drm_bo_t *bo)
+{
+ struct gralloc_drm_handle_t *handle = bo->handle;
+ int imported = bo->imported;
+
+ bo->drm->drv->free(bo->drm->drv, bo);
+ if (imported) {
+ handle->data_owner = 0;
+ handle->data = 0;
+ }
+ else {
+ free(handle);
+ }
+}
+
+/*
+ * Map a bo for CPU access.
+ */
+int gralloc_drm_bo_map(struct gralloc_drm_bo_t *bo,
+ int x, int y, int w, int h,
+ int enable_write, void **addr)
+{
+ return bo->drm->drv->map(bo->drm->drv, bo,
+ x, y, w, h, enable_write, addr);
+}
+
+/*
+ * Unmap a bo.
+ */
+void gralloc_drm_bo_unmap(struct gralloc_drm_bo_t *bo)
+{
+ bo->drm->drv->unmap(bo->drm->drv, bo);
+}
+
+/*
+ * 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;
+}
diff --git a/gralloc_drm.h b/gralloc_drm.h
new file mode 100644
index 0000000..67f3598
--- /dev/null
+++ b/gralloc_drm.h
@@ -0,0 +1,84 @@
+/*
+ * 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>
+
+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_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_RGBA_5551:
+ case HAL_PIXEL_FORMAT_RGBA_4444:
+ bpp = 2;
+ break;
+ default:
+ bpp = 0;
+ break;
+ }
+
+ return bpp;
+}
+
+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 *gralloc_drm_bo_validate(struct gralloc_drm_t *drm, buffer_handle_t handle);
+void gralloc_drm_bo_destroy(struct gralloc_drm_bo_t *bo);
+
+int gralloc_drm_bo_map(struct gralloc_drm_bo_t *bo, int x, int y, int w, int h, int enable_write, void **addr);
+void gralloc_drm_bo_unmap(struct gralloc_drm_bo_t *bo);
+buffer_handle_t gralloc_drm_bo_get_handle(struct gralloc_drm_bo_t *bo, int *stride);
+
+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);
+
+#endif /* _GRALLOC_DRM_H_ */
diff --git a/gralloc_drm_handle.h b/gralloc_drm_handle.h
new file mode 100644
index 0000000..343ace0
--- /dev/null
+++ b/gralloc_drm_handle.h
@@ -0,0 +1,63 @@
+/*
+ * 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>
+
+struct gralloc_drm_handle_t {
+ native_handle_t base;
+
+#define GRALLOC_DRM_HANDLE_MAGIC 0x12345678
+#define GRALLOC_DRM_HANDLE_NUM_INTS 9
+#define GRALLOC_DRM_HANDLE_NUM_FDS 0
+ int magic;
+
+ int width;
+ int height;
+ int format;
+ int usage;
+
+ 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->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;
+}
+
+#endif /* _GRALLOC_DRM_HANDLE_H_ */
diff --git a/gralloc_drm_intel.c b/gralloc_drm_intel.c
new file mode 100644
index 0000000..e5ddcfc
--- /dev/null
+++ b/gralloc_drm_intel.c
@@ -0,0 +1,585 @@
+/*
+ * 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;
+};
+
+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) {
+ LOGE("failed to subdata batch");
+ goto fail;
+ }
+ ret = drm_intel_bo_exec(info->batch_ibo, size, NULL, 0, 0);
+ if (ret) {
+ LOGE("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_copy(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *dst,
+ struct gralloc_drm_bo_t *src,
+ short x1, short y1, short x2, short 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;
+
+ if (dst->handle->width != src->handle->width ||
+ dst->handle->height != src->handle->height ||
+ dst->handle->stride != src->handle->stride ||
+ dst->handle->format != src->handle->format) {
+ LOGE("copy between incompatible buffers");
+ return;
+ }
+
+ if (x1 < 0)
+ x1 = 0;
+ if (y1 < 0)
+ y1 = 0;
+ if (x2 > dst->handle->width)
+ x2 = dst->handle->width;
+ if (y2 > dst->handle->height)
+ y2 = dst->handle->height;
+
+ if (x2 <= x1 || y2 <= y1)
+ return;
+
+ 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;
+
+ 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:
+ LOGE("copy with unsupported format");
+ 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 | dst_pitch);
+ batch_dword(info, (y1 << 16) | x1);
+ batch_dword(info, (y2 << 16) | x2);
+ batch_reloc(info, dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+ batch_dword(info, (y1 << 16) | x1);
+ batch_dword(info, 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) {
+ LOGE("unrecognized format 0x%x", handle->format);
+ return NULL;
+ }
+
+ 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 = (handle->width + 63) & ~63;
+ aligned_height = handle->height;
+ 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 = (handle->width + 3) & ~3;
+ aligned_height = (handle->height + 1) & ~1;
+ }
+ else {
+ name = "gralloc-buffer";
+ aligned_width = handle->width;
+ aligned_height = handle->height;
+ }
+
+ 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) {
+ LOGE("failed to create ibo from name %u",
+ handle->name);
+ free(ib);
+ return NULL;
+ }
+
+ if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) {
+ LOGE("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) {
+ LOGE("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)) {
+ LOGE("failed to flink ibo");
+ drm_intel_bo_unreference(ib->ibo);
+ free(ib);
+ return NULL;
+ }
+ }
+
+ if (handle->usage & GRALLOC_USAGE_HW_FB)
+ 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 "dri/intel_chipset.h" /* for IS_965() */
+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;
+
+ drm->mode_dirty_fb = 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;
+
+ if (IS_965(id)) {
+ 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->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) {
+ LOGE("failed to allocate driver info");
+ return NULL;
+ }
+
+ info->fd = fd;
+ info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024);
+ if (!info->bufmgr) {
+ LOGE("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.copy = intel_copy;
+
+ return &info->base;
+}
diff --git a/gralloc_drm_kms.c b/gralloc_drm_kms.c
new file mode 100644
index 0000000..c64d4ad
--- /dev/null
+++ b/gralloc_drm_kms.c
@@ -0,0 +1,499 @@
+/*
+ * 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/log.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include "gralloc_drm.h"
+#include "gralloc_drm_priv.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);
+}
+
+/*
+ * Add a fb object for a bo.
+ */
+int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
+{
+ uint8_t bpp;
+
+ if (bo->fb_id)
+ return 0;
+
+ bpp = gralloc_drm_get_bpp(bo->handle->format) * 8;
+
+ return drmModeAddFB(bo->drm->fd,
+ bo->handle->width, bo->handle->height, bpp, bpp,
+ bo->handle->stride, bo->fb_handle,
+ (uint32_t *) &bo->fb_id);
+}
+
+/*
+ * 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, int fb_id)
+{
+ int ret;
+
+ ret = drmModeSetCrtc(drm->fd, drm->crtc_id, fb_id,
+ 0, 0, &drm->connector_id, 1, &drm->mode);
+ if (ret) {
+ LOGE("failed to set crtc");
+ return ret;
+ }
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+ if (drm->mode_dirty_fb)
+ ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
+#endif
+
+ 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;
+}
+
+/*
+ * 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 */
+ LOGE("drmHandleEvent returned without flipping");
+ drm->current_front = drm->next_front;
+ drm->next_front = NULL;
+ }
+ }
+
+ if (!bo)
+ return 0;
+
+ ret = drmModePageFlip(drm->fd, drm->crtc_id, bo->fb_id,
+ DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
+ if (ret)
+ LOGE("failed to perform page flip");
+ 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;
+
+ 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) {
+ LOGW("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) {
+ LOGW("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) {
+ LOGE("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->copy(drm->drv, dst, bo, 0, 0,
+ bo->handle->width,
+ bo->handle->height);
+ bo = dst;
+ }
+
+ drm_kms_wait_for_post(drm, 0);
+ ret = drm_kms_set_crtc(drm, bo->fb_id);
+ if (!ret) {
+ drm->first_post = 0;
+ drm->current_front = bo;
+ if (drm->next_front == bo)
+ drm->next_front = NULL;
+ }
+
+ 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->copy(drm->drv, drm->current_front,
+ bo, 0, 0,
+ bo->handle->width,
+ bo->handle->height);
+ ret = 0;
+ break;
+ case DRM_SWAP_SETCRTC:
+ drm_kms_wait_for_post(drm, 0);
+ ret = drm_kms_set_crtc(drm, bo->fb_id);
+ 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 sigaction act;
+
+ /* wait the pending flip */
+ if (drm_singleton && drm_singleton->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->mode.hdisplay,
+ drm->mode.vdisplay,
+ drm->format,
+ GRALLOC_USAGE_HW_FB);
+ if (front && gralloc_drm_bo_add_fb(front)) {
+ gralloc_drm_bo_destroy(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;
+ }
+
+ LOGD("will use %s for fb posting", swap_mode);
+}
+
+/*
+ * Initialize KMS with a connector.
+ */
+static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
+ drmModeConnectorPtr connector)
+{
+ drmModeEncoderPtr encoder;
+ drmModeModeInfoPtr mode;
+ int i;
+
+ if (!connector->count_modes)
+ return -EINVAL;
+
+ encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
+ if (!encoder)
+ return -EINVAL;
+
+ for (i = 0; i < drm->resources->count_crtcs; i++) {
+ if (encoder->possible_crtcs & (1 << i))
+ break;
+ }
+ drmModeFreeEncoder(encoder);
+ if (i == drm->resources->count_crtcs)
+ return -EINVAL;
+
+ drm->crtc_id = drm->resources->crtcs[i];
+ drm->connector_id = connector->connector_id;
+
+ /* find the first preferred mode */
+ mode = NULL;
+ for (i = 0; i < connector->count_modes; i++) {
+ drmModeModeInfoPtr m = &connector->modes[i];
+ if (m->type & DRM_MODE_TYPE_PREFERRED) {
+ mode = m;
+ break;
+ }
+ }
+ /* no preference; use the first */
+ if (!mode)
+ mode = &connector->modes[0];
+
+ drm->mode = *mode;
+
+ if (connector->mmWidth && connector->mmHeight) {
+ drm->xdpi = (drm->mode.hdisplay * 25.4 / connector->mmWidth);
+ drm->ydpi = (drm->mode.vdisplay * 25.4 / connector->mmHeight);
+ }
+ else {
+ drm->xdpi = 75;
+ drm->ydpi = 75;
+ }
+
+ /* select between 32/16 bits */
+#if 1
+ drm->format = HAL_PIXEL_FORMAT_BGRA_8888;
+#else
+ drm->format = HAL_PIXEL_FORMAT_RGB_565;
+#endif
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+ drm->clip.x1 = 0;
+ drm->clip.y1 = 0;
+ drm->clip.x2 = drm->mode.hdisplay;
+ drm->clip.y2 = drm->mode.vdisplay;
+#endif
+
+ return 0;
+}
+
+/*
+ * Initialize KMS.
+ */
+int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
+{
+ int i, ret;
+
+ if (drm->resources)
+ return 0;
+
+ drm->resources = drmModeGetResources(drm->fd);
+ if (!drm->resources) {
+ LOGE("failed to get modeset resources");
+ return -EINVAL;
+ }
+
+ /* find the crtc/connector/mode to use */
+ 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,
+ connector))
+ break;
+ }
+
+ drmModeFreeConnector(connector);
+ }
+ }
+ if (i == drm->resources->count_connectors) {
+ LOGE("failed to find a valid crtc/connector/mode combination");
+ drmModeFreeResources(drm->resources);
+ drm->resources = NULL;
+
+ return -EINVAL;
+ }
+
+ drm_kms_init_features(drm);
+ drm->first_post = 1;
+
+ return 0;
+}
+
+/*
+ * 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->mode.hdisplay;
+ *((uint32_t *) &fb->height) = drm->mode.vdisplay;
+ *((int *) &fb->stride) = drm->mode.hdisplay;
+ *((float *) &fb->fps) = drm->mode.vrefresh;
+
+ *((int *) &fb->format) = drm->format;
+ *((float *) &fb->xdpi) = drm->xdpi;
+ *((float *) &fb->ydpi) = drm->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/gralloc_drm_priv.h b/gralloc_drm_priv.h
new file mode 100644
index 0000000..6891faa
--- /dev/null
+++ b/gralloc_drm_priv.h
@@ -0,0 +1,115 @@
+/*
+ * 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 <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "gralloc_drm_handle.h"
+
+/* how a bo is posted */
+enum drm_swap_mode {
+ DRM_SWAP_NOOP,
+ DRM_SWAP_FLIP,
+ DRM_SWAP_COPY,
+ DRM_SWAP_SETCRTC,
+};
+
+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;
+ uint32_t crtc_id;
+ uint32_t connector_id;
+ drmModeModeInfo mode;
+ int xdpi, ydpi;
+ int format;
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+ drmModeClip clip;
+#endif
+ drmEventContext evctx;
+
+ /* initialized by drv->init_kms_features */
+ enum drm_swap_mode swap_mode;
+ int swap_interval;
+ int mode_dirty_fb;
+ int mode_sync_flip; /* page flip should block */
+ int vblank_secondary;
+
+ int first_post;
+ struct gralloc_drm_bo_t *current_front, *next_front;
+ int waiting_flip;
+ unsigned int last_swap;
+};
+
+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);
+
+ /* copy between two bo's, used for DRM_SWAP_COPY */
+ void (*copy)(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *dst,
+ struct gralloc_drm_bo_t *src,
+ short x1, short y1, short x2, short y2);
+};
+
+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 */
+};
+
+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_pipe(int fd);
+
+#endif /* _GRALLOC_DRM_PRIV_H_ */
diff --git a/gralloc_drm_radeon.c b/gralloc_drm_radeon.c
new file mode 100644
index 0000000..59fb782
--- /dev/null
+++ b/gralloc_drm_radeon.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ *
+ * Based on xf86-video-ati, which has
+ *
+ * Copyright © 2009 Red Hat, 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.
+ */
+
+/* XXX This driver assumes evergreen. */
+
+#define LOG_TAG "GRALLOC-RADEON"
+
+#include <cutils/log.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <drm.h>
+#include <radeon_drm.h>
+#include <radeon_bo_gem.h>
+#include <radeon_bo.h>
+
+#include "gralloc_drm.h"
+#include "gralloc_drm_priv.h"
+
+#define RADEON_GPU_PAGE_SIZE 4096
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1))
+
+struct radeon_info {
+ struct gralloc_drm_drv_t base;
+
+ int fd;
+ struct radeon_bo_manager *bufmgr;
+
+ uint32_t tile_config;
+ int num_channels;
+ int num_banks;
+ int group_bytes;
+ /* r6xx+ tile config */
+ int have_tiling_info;
+ int allow_color_tiling;
+};
+
+struct radeon_buffer {
+ struct gralloc_drm_bo_t base;
+
+ struct radeon_bo *rbo;
+};
+
+static int eg_init_tile_config(struct radeon_info *info)
+{
+ struct drm_radeon_info ginfo;
+ uint32_t val;
+ int ret;
+
+ memset(&ginfo, 0, sizeof(ginfo));
+ ginfo.request = RADEON_INFO_TILING_CONFIG;
+ ginfo.value = (long) &val;
+ ret = drmCommandWriteRead(info->fd, DRM_RADEON_INFO,
+ &ginfo, sizeof(ginfo));
+ if (ret)
+ return ret;
+
+ info->tile_config = val;
+
+ switch (info->tile_config & 0xf) {
+ case 0:
+ info->num_channels = 1;
+ break;
+ case 1:
+ info->num_channels = 2;
+ break;
+ case 2:
+ info->num_channels = 4;
+ break;
+ case 3:
+ info->num_channels = 8;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ info->num_banks = (info->tile_config & 0xf0) >> 4;
+
+ switch ((info->tile_config & 0xf00) >> 8) {
+ case 0:
+ info->group_bytes = 256;
+ break;
+ case 1:
+ info->group_bytes = 512;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ info->have_tiling_info = 1;
+ info->allow_color_tiling = 0;
+
+ return 0;
+}
+
+/* returns pitch alignment in pixels */
+static int eg_get_pitch_align(struct radeon_info *info, int bpe, uint32_t tiling)
+{
+ int pitch_align = 1;
+
+ if (tiling & RADEON_TILING_MACRO) {
+ /* general surface requirements */
+ pitch_align = (((info->group_bytes / 8) / bpe) *
+ info->num_banks) * 8;
+ /* further restrictions for scanout */
+ pitch_align = MAX(info->num_banks * 8, pitch_align);
+ } else if (tiling & RADEON_TILING_MICRO) {
+ /* general surface requirements */
+ pitch_align = MAX(8, (info->group_bytes / (8 * bpe)));
+ /* further restrictions for scanout */
+ pitch_align = MAX(info->group_bytes / bpe, pitch_align);
+ } else {
+ if (info->have_tiling_info)
+ /* linear aligned requirements */
+ pitch_align = MAX(64, info->group_bytes / bpe);
+ else
+ /* default to 512 elements if we don't know the real
+ * group size otherwise the kernel may reject the CS
+ * if the group sizes don't match as the pitch won't
+ * be aligned properly.
+ */
+ pitch_align = 512;
+ }
+
+ return pitch_align;
+}
+
+/* returns height alignment in pixels */
+static int eg_get_height_align(struct radeon_info *info, uint32_t tiling)
+{
+ int height_align = 1;
+
+ if (tiling & RADEON_TILING_MACRO)
+ height_align = info->num_channels * 8;
+ else if (tiling & RADEON_TILING_MICRO)
+ height_align = 8;
+ else
+ height_align = 8;
+
+ return height_align;
+}
+
+/* returns base alignment in bytes */
+static int eg_get_base_align(struct radeon_info *info,
+ int bpe, uint32_t tiling)
+{
+ int pixel_align = eg_get_pitch_align(info, bpe, tiling);
+ int height_align = eg_get_height_align(info, tiling);
+ int base_align = RADEON_GPU_PAGE_SIZE;
+
+ if (tiling & RADEON_TILING_MACRO) {
+ base_align =
+ MAX(info->num_banks * info->num_channels * 8 * 8 * bpe,
+ pixel_align * bpe * height_align);
+ }
+ else {
+ if (info->have_tiling_info)
+ base_align = info->group_bytes;
+ else
+ /* default to 512 if we don't know the real
+ * group size otherwise the kernel may reject the CS
+ * if the group sizes don't match as the base won't
+ * be aligned properly.
+ */
+ base_align = 512;
+ }
+
+ return base_align;
+}
+
+static uint32_t drm_gem_get_tiling(const struct gralloc_drm_handle_t *handle)
+{
+ return 0;
+}
+
+static struct gralloc_drm_bo_t *
+drm_gem_radeon_alloc(struct gralloc_drm_drv_t *drv, struct gralloc_drm_handle_t *handle)
+{
+ struct radeon_info *info = (struct radeon_info *) drv;
+ struct radeon_buffer *rbuf;
+ uint32_t tiling, domain;
+ int cpp;
+
+ tiling = drm_gem_get_tiling(handle);
+ domain = RADEON_GEM_DOMAIN_VRAM;
+ cpp = gralloc_drm_get_bpp(handle->format);
+ if (!cpp) {
+ LOGE("unrecognized format 0x%x", handle->format);
+ return NULL;
+ }
+
+ rbuf = calloc(1, sizeof(*rbuf));
+ if (!rbuf)
+ return NULL;
+
+
+ if (handle->name) {
+ rbuf->rbo = radeon_bo_open(info->bufmgr, handle->name,
+ 0, 0, domain, 0);
+ if (!rbuf->rbo) {
+ LOGE("failed to create rbo from name %u",
+ handle->name);
+ free(rbuf);
+ return NULL;
+ }
+ }
+ else {
+ int aligned_width, aligned_height;
+ int pitch, size, base_align;
+
+ if (handle->usage & (GRALLOC_USAGE_HW_FB |
+ GRALLOC_USAGE_HW_TEXTURE)) {
+ aligned_width = ALIGN(handle->width,
+ eg_get_pitch_align(info, cpp, tiling));
+ aligned_height = ALIGN(handle->height,
+ eg_get_height_align(info, tiling));
+ }
+ else {
+ aligned_width = handle->width;
+ aligned_height = handle->height;
+ }
+
+ if (!(handle->usage & (GRALLOC_USAGE_HW_FB |
+ GRALLOC_USAGE_HW_RENDER)) &&
+ (handle->usage & GRALLOC_USAGE_SW_READ_OFTEN))
+ domain = RADEON_GEM_DOMAIN_GTT;
+
+ pitch = aligned_width * cpp;
+ size = ALIGN(aligned_height * pitch, RADEON_GPU_PAGE_SIZE);
+ base_align = eg_get_base_align(info, cpp, tiling);
+
+ rbuf->rbo = radeon_bo_open(info->bufmgr, 0,
+ size, base_align, domain, 0);
+ if (!rbuf->rbo) {
+ LOGE("failed to allocate rbo %dx%dx%d",
+ handle->width, handle->height, cpp);
+ free(rbuf);
+ return NULL;
+ }
+
+ if (tiling)
+ radeon_bo_set_tiling(rbuf->rbo, tiling, pitch);
+
+ if (radeon_gem_get_kernel_name(rbuf->rbo,
+ (uint32_t *) &handle->name)) {
+ LOGE("failed to flink rbo");
+ radeon_bo_unref(rbuf->rbo);
+ free(rbuf);
+ return NULL;
+ }
+
+ handle->stride = pitch;
+ }
+
+ if (handle->usage & GRALLOC_USAGE_HW_FB)
+ rbuf->base.fb_handle = rbuf->rbo->handle;
+
+ rbuf->base.handle = handle;
+
+ return &rbuf->base;
+}
+
+static void drm_gem_radeon_free(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo)
+{
+ struct radeon_buffer *rbuf = (struct radeon_buffer *) bo;
+ radeon_bo_unref(rbuf->rbo);
+}
+
+static int drm_gem_radeon_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 radeon_buffer *rbuf = (struct radeon_buffer *) bo;
+ int err;
+
+ err = radeon_bo_map(rbuf->rbo, enable_write);
+ if (!err)
+ *addr = rbuf->rbo->ptr;
+
+ return err;
+}
+
+static void drm_gem_radeon_unmap(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_bo_t *bo)
+{
+ struct radeon_buffer *rbuf = (struct radeon_buffer *) bo;
+ radeon_bo_unmap(rbuf->rbo);
+}
+
+static void drm_gem_radeon_init_kms_features(struct gralloc_drm_drv_t *drv,
+ struct gralloc_drm_t *drm)
+{
+ drm->mode_dirty_fb = 0;
+ drm->swap_mode = DRM_SWAP_FLIP;
+ drm->mode_sync_flip = 1;
+ drm->swap_interval = 1;
+ drm->vblank_secondary = 0;
+}
+
+static void drm_gem_radeon_destroy(struct gralloc_drm_drv_t *drv)
+{
+ struct radeon_info *info = (struct radeon_info *) drv;
+
+ radeon_bo_manager_gem_dtor(info->bufmgr);
+ free(info);
+}
+
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_radeon(int fd)
+{
+ struct radeon_info *info;
+
+ info = calloc(1, sizeof(*info));
+ if (!info)
+ return NULL;
+
+ info->fd = fd;
+ info->bufmgr = radeon_bo_manager_gem_ctor(info->fd);
+ if (!info->bufmgr) {
+ LOGE("failed to create buffer manager");
+ free(info);
+ return NULL;
+ }
+
+ if (eg_init_tile_config(info)) {
+ radeon_bo_manager_gem_dtor(info->bufmgr);
+ free(info);
+ return NULL;
+ }
+
+ info->base.destroy = drm_gem_radeon_destroy;
+ info->base.init_kms_features = drm_gem_radeon_init_kms_features;
+ info->base.alloc = drm_gem_radeon_alloc;
+ info->base.free = drm_gem_radeon_free;
+ info->base.map = drm_gem_radeon_map;
+ info->base.unmap = drm_gem_radeon_unmap;
+
+ return &info->base;
+}