summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChia-I Wu <olv@lunarg.com>2010-10-11 16:06:47 +0800
committerChia-I Wu <olvaffe@gmail.com>2011-03-16 20:18:39 +0800
commit2b1f1af17f8e8f199cb0dd4f7f1a225529b357c5 (patch)
tree938719b6cb9f40fba9a9af658b7223bdf0aa4f7e
parent8e698931d730242cdb88fd7281903a10c6576d09 (diff)
android: Add DRM-based gralloc.
-rw-r--r--src/gralloc/gralloc_gem.c119
-rw-r--r--src/gralloc/gralloc_gem.h77
-rw-r--r--src/gralloc/gralloc_gem_i915.c211
-rw-r--r--src/gralloc/gralloc_gem_pipe.c333
-rw-r--r--src/gralloc/gralloc_kms.c243
-rw-r--r--src/gralloc/gralloc_kms.h19
-rw-r--r--src/gralloc/gralloc_mod.c328
-rw-r--r--src/gralloc/gralloc_mod.h65
8 files changed, 1395 insertions, 0 deletions
diff --git a/src/gralloc/gralloc_gem.c b/src/gralloc/gralloc_gem.c
new file mode 100644
index 0000000000..a3df97f89b
--- /dev/null
+++ b/src/gralloc/gralloc_gem.c
@@ -0,0 +1,119 @@
+#define LOG_TAG "GRALLOC-GEM"
+
+#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_mod.h"
+#include "gralloc_gem.h"
+
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+#define DRM_PATH "/dev/dri/card0"
+
+static int32_t drm_gem_pid = 0;
+
+static int
+drm_gem_get_pid(void)
+{
+ if (unlikely(!drm_gem_pid))
+ android_atomic_write((int32_t) getpid(), &drm_gem_pid);
+ return drm_gem_pid;
+}
+
+static int
+drm_gem_init_locked(struct drm_module_t *drm)
+{
+ int ret;
+
+ if (drm->fd >= 0)
+ return 0;
+
+ drm->fd = open(DRM_PATH, O_RDWR);
+ if (drm->fd < 0) {
+ LOGE("failed to open %s", DRM_PATH);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int
+drm_gem_init(struct drm_module_t *drm)
+{
+ int ret;
+
+ pthread_mutex_lock(&drm->mutex);
+ ret = drm_gem_init_locked(drm);
+ pthread_mutex_unlock(&drm->mutex);
+
+ return ret;
+}
+
+int
+drm_gem_get_magic(struct drm_module_t *drm, int32_t *magic)
+{
+ int ret;
+
+ ret = drm_gem_init(drm);
+ if (ret)
+ return ret;
+
+ return drmGetMagic(drm->fd, (drm_magic_t *) magic);
+}
+
+int
+drm_gem_auth_magic(struct drm_module_t *drm, int32_t magic)
+{
+ int ret;
+
+ ret = drm_gem_init(drm);
+ if (ret)
+ return ret;
+
+ return drmAuthMagic(drm->fd, (drm_magic_t) magic);
+}
+
+struct drm_bo_t *
+drm_gem_create_bo(int width, int height, int format, int usage)
+{
+ struct drm_bo_t *bo;
+
+ bo = calloc(1, sizeof(*bo));
+ if (!bo)
+ return NULL;
+
+ bo->base.version = sizeof(bo->base);
+ bo->base.numInts = DRM_HANDLE_NUM_INTS;
+ bo->base.numFds = DRM_HANDLE_NUM_FDS;
+
+ bo->magic = DRM_HANDLE_MAGIC;
+
+ bo->width = width;
+ bo->height = height;
+ bo->format = format;
+ bo->usage = usage;
+
+ bo->pid = drm_gem_get_pid();
+
+ return bo;
+}
+
+struct drm_bo_t *
+drm_gem_validate(buffer_handle_t handle)
+{
+ struct drm_bo_t *bo = drm_gem_get(handle);
+
+ if (bo && unlikely(bo->pid != drm_gem_pid)) {
+ bo->pid = drm_gem_get_pid();
+ bo->fb_handle = 0;
+ bo->fb_id = 0;
+ bo->data = 0;
+ }
+
+ return bo;
+}
diff --git a/src/gralloc/gralloc_gem.h b/src/gralloc/gralloc_gem.h
new file mode 100644
index 0000000000..e6ef176efa
--- /dev/null
+++ b/src/gralloc/gralloc_gem.h
@@ -0,0 +1,77 @@
+#ifndef _GRALLOC_GEM_H_
+#define _GRALLOC_GEM_H_
+
+#include <cutils/native_handle.h>
+#include "gralloc_mod.h"
+
+struct drm_bo_t {
+ native_handle_t base;
+
+#define DRM_HANDLE_MAGIC 0x12345678
+#define DRM_HANDLE_NUM_INTS 11
+#define DRM_HANDLE_NUM_FDS 0
+ int magic;
+
+ int width;
+ int height;
+ int format;
+ int usage;
+
+ int name;
+ int stride;
+
+ /* these fields are undefined until validated */
+ int pid;
+ int fb_handle;
+ int fb_id;
+ int data; /* pointer as int? 32-bit only! */
+};
+
+int
+drm_gem_init(struct drm_module_t *drm);
+
+int
+drm_gem_get_magic(struct drm_module_t *drm, int32_t *magic);
+
+int
+drm_gem_auth_magic(struct drm_module_t *drm, int32_t magic);
+
+static inline struct drm_bo_t *
+drm_gem_get(buffer_handle_t handle)
+{
+ struct drm_bo_t *bo = (struct drm_bo_t *) handle;
+
+ if (bo->base.version != sizeof(bo->base) ||
+ bo->base.numInts != DRM_HANDLE_NUM_INTS ||
+ bo->base.numFds != DRM_HANDLE_NUM_FDS ||
+ bo->magic != DRM_HANDLE_MAGIC)
+ bo = NULL;
+
+ return bo;
+}
+
+struct drm_bo_t *
+drm_gem_validate(buffer_handle_t handle);
+
+struct drm_bo_t *
+drm_gem_create_bo(int width, int height, int format, int usage);
+
+
+int
+drm_gem_drv_init(struct drm_module_t *drm);
+
+struct drm_bo_t *
+drm_gem_drv_alloc(struct drm_module_t *drm, int width, int height,
+ int format, int usage, int *stride);
+
+void
+drm_gem_drv_free(struct drm_module_t *drm, struct drm_bo_t *bo);
+
+int
+drm_gem_drv_map(struct drm_module_t *drm, struct drm_bo_t *bo,
+ int x, int y, int w, int h, int enable_write, void **addr);
+
+void
+drm_gem_drv_unmap(struct drm_module_t *drm, struct drm_bo_t *bo);
+
+#endif /* _GRALLOC_GEM_H_ */
diff --git a/src/gralloc/gralloc_gem_i915.c b/src/gralloc/gralloc_gem_i915.c
new file mode 100644
index 0000000000..2822fe5c12
--- /dev/null
+++ b/src/gralloc/gralloc_gem_i915.c
@@ -0,0 +1,211 @@
+#define LOG_TAG "GRALLOC-I915"
+
+#include <cutils/log.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <drm.h>
+#include <intel_bufmgr.h>
+#include <i915_drm.h>
+
+#include "gralloc_mod.h"
+#include "gralloc_gem.h"
+
+static void
+drm_gem_drv_init_features_locked(struct drm_module_t *drm)
+{
+ struct drm_i915_getparam gp;
+
+ drm_intel_bufmgr *bufmgr = (drm_intel_bufmgr *) drm->gem;
+
+ drm->mode_dirty_fb = 0;
+
+ memset(&gp, 0, sizeof(gp));
+ gp.param = I915_PARAM_HAS_PAGEFLIPPING;
+ gp.value = &drm->mode_page_flip;
+ if (!drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
+ drm->mode_page_flip = *gp.value;
+ else
+ drm->mode_page_flip = 0;
+
+ if (drm->resources) {
+ int pipe;
+
+ pipe = drm_intel_get_pipe_from_crtc_id(bufmgr, drm->crtc_id);
+ drm->swap_interval = (pipe >= 0) ? 1 : 0;
+ drm->vblank_secondary = (pipe > 0);
+ }
+ else {
+ drm->swap_interval = 0;
+ }
+
+ /* XXX there is a bug in the kernel module */
+ drm->mode_page_flip = 0;
+
+}
+
+static int
+drm_gem_drv_init_locked(struct drm_module_t *drm)
+{
+ if (drm->gem)
+ return 0;
+
+ drm->gem = (void *) drm_intel_bufmgr_gem_init(drm->fd, 16 * 1024);
+ if (!drm->gem) {
+ LOGE("failed to create buffer manager");
+ return -ENOMEM;
+ }
+
+ drm_gem_drv_init_features_locked(drm);
+
+ return 0;
+}
+
+int
+drm_gem_drv_init(struct drm_module_t *drm)
+{
+ int ret;
+
+ pthread_mutex_lock(&drm->mutex);
+ ret = drm_gem_drv_init_locked(drm);
+ pthread_mutex_unlock(&drm->mutex);
+
+ return ret;
+}
+
+static uint32_t
+drm_gem_get_tiling(struct drm_bo_t *bo)
+{
+ uint32_t tiling = I915_TILING_NONE;
+
+ if (bo->usage & GRALLOC_USAGE_SW_READ_OFTEN)
+ return tiling;
+
+ if (bo->usage & GRALLOC_USAGE_HW_FB ||
+ bo->usage & GRALLOC_USAGE_HW_TEXTURE) {
+ if (bo->width >= 64)
+ tiling = I915_TILING_X;
+ }
+
+ return tiling;
+}
+
+struct drm_bo_t *
+drm_gem_drv_alloc(struct drm_module_t *drm, int width, int height,
+ int format, int usage, int *stride)
+{
+ drm_intel_bufmgr *bufmgr = (drm_intel_bufmgr *) drm->gem;
+ struct drm_bo_t *bo;
+ drm_intel_bo *ibo;
+ int aligned_width, aligned_height, cpp;
+ unsigned long pitch, flags;
+ uint32_t tiling;
+ const char *name;
+
+ bo = drm_gem_create_bo(width, height, format, usage);
+ if (!bo)
+ return NULL;
+
+ cpp = drm_mod_get_bpp(format);
+ if (!cpp) {
+ LOGE("unrecognized format 0x%x", format);
+ free(bo);
+ return NULL;
+ }
+
+ if (usage & GRALLOC_USAGE_HW_FB) {
+ name = "gralloc-fb";
+ aligned_width = (width + 63) & ~63;
+ }
+ if (usage & GRALLOC_USAGE_HW_TEXTURE) {
+ name = "gralloc-texture";
+ aligned_width = (width + 3) & ~3;
+ aligned_height = (height + 1) & ~1;
+ }
+ else {
+ name = "gralloc-buf";
+ aligned_width = width;
+ aligned_height = height;
+ }
+
+ tiling = drm_gem_get_tiling(bo);
+
+ flags = 0x0;
+ if (bo->usage & (GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_FB))
+ flags |= BO_ALLOC_FOR_RENDER;
+
+ ibo = drm_intel_bo_alloc_tiled(bufmgr, name,
+ aligned_width, aligned_height, cpp, &tiling, &pitch, flags);
+ if (!ibo) {
+ LOGE("failed to allocate ibo %dx%dx%d", width, height, cpp);
+ free(bo);
+ return NULL;
+ }
+
+ if (bo->usage & GRALLOC_USAGE_HW_FB) {
+ drm_intel_bo_disable_reuse(ibo);
+ bo->stride = pitch;
+ bo->fb_handle = ibo->handle;
+ }
+
+ if (drm_intel_bo_flink(ibo, (uint32_t *) &bo->name)) {
+ LOGE("failed to flink ibo");
+ drm_intel_bo_unreference(ibo);
+ free(bo);
+ return NULL;
+ }
+
+ bo->data = (int) ibo;
+
+ *stride = pitch;
+
+ return bo;
+}
+
+void
+drm_gem_drv_free(struct drm_module_t *drm, struct drm_bo_t *bo)
+{
+ drm_intel_bo_unreference((drm_intel_bo *) bo->data);
+ free(bo);
+}
+
+int
+drm_gem_drv_map(struct drm_module_t *drm, struct drm_bo_t *bo,
+ int x, int y, int w, int h, int enable_write, void **addr)
+{
+ drm_intel_bo *ibo = (drm_intel_bo *) bo->data;
+ int err;
+
+ if (!ibo) {
+ drm_intel_bufmgr *bufmgr = (drm_intel_bufmgr *) drm->gem;
+
+ ibo = drm_intel_bo_gem_create_from_name(bufmgr, "gralloc-r", bo->name);
+ if (!ibo) {
+ LOGE("failed to create ibo from name %u", bo->name);
+ return -EINVAL;
+ }
+
+ bo->data = (int) ibo;
+ }
+
+ if ((bo->usage & GRALLOC_USAGE_HW_FB) ||
+ drm_gem_get_tiling(bo) != I915_TILING_NONE)
+ err = drm_intel_gem_bo_map_gtt(ibo);
+ else
+ err = drm_intel_bo_map(ibo, enable_write);
+ if (!err)
+ *addr = ibo->virtual;
+
+ return err;
+}
+
+void
+drm_gem_drv_unmap(struct drm_module_t *drm, struct drm_bo_t *bo)
+{
+ drm_intel_bo *ibo = (drm_intel_bo *) bo->data;
+
+ if ((bo->usage & GRALLOC_USAGE_HW_FB) ||
+ drm_gem_get_tiling(bo) != I915_TILING_NONE)
+ drm_intel_gem_bo_unmap_gtt(ibo);
+ else
+ drm_intel_bo_unmap(ibo);
+}
diff --git a/src/gralloc/gralloc_gem_pipe.c b/src/gralloc/gralloc_gem_pipe.c
new file mode 100644
index 0000000000..99a8461627
--- /dev/null
+++ b/src/gralloc/gralloc_gem_pipe.c
@@ -0,0 +1,333 @@
+#define LOG_TAG "GRALLOC-PIPE"
+
+#include <cutils/log.h>
+#include <errno.h>
+
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "state_tracker/drm_driver.h"
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+
+#include "gralloc_mod.h"
+#include "gralloc_gem.h"
+
+struct drm_pipe_manager {
+ pthread_mutex_t mutex;
+ struct pipe_screen *screen;
+ struct pipe_context *context;
+};
+
+struct drm_pipe_buffer {
+ struct winsys_handle winsys;
+ uint32_t fb_handle;
+ struct pipe_resource *resource;
+ struct pipe_transfer *transfer;
+};
+
+static void
+drm_gem_drv_init_features_locked(struct drm_module_t *drm)
+{
+ drm->mode_dirty_fb = 0;
+ drm->mode_page_flip = 0;
+
+ if (strcmp(driver_descriptor.driver_name, "vmwgfx") == 0)
+ drm->mode_dirty_fb = 1;
+
+ drm->swap_interval = 0;
+}
+
+static int
+drm_gem_drv_init_locked(struct drm_module_t *drm)
+{
+ struct drm_pipe_manager *pm;
+
+ if (drm->gem)
+ return 0;
+
+ pm = CALLOC(1, sizeof(*pm));
+ if (!pm)
+ return -ENOMEM;
+
+ pthread_mutex_init(&pm->mutex, NULL);
+
+ pm->screen = driver_descriptor.create_screen(drm->fd);
+ if (!pm->screen) {
+ LOGE("failed to create pipe screen");
+ FREE(pm);
+ return -EINVAL;
+ }
+
+ drm->gem = (void *) pm;
+
+ drm_gem_drv_init_features_locked(drm);
+
+ return 0;
+}
+
+int
+drm_gem_drv_init(struct drm_module_t *drm)
+{
+ int ret;
+
+ pthread_mutex_lock(&drm->mutex);
+ ret = drm_gem_drv_init_locked(drm);
+ pthread_mutex_unlock(&drm->mutex);
+
+ return ret;
+}
+
+static enum pipe_format
+get_pipe_format(int format)
+{
+ enum pipe_format fmt;
+
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ fmt = PIPE_FORMAT_R8G8B8A8_UNORM;
+ break;
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ fmt = PIPE_FORMAT_R8G8B8X8_UNORM;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ fmt = PIPE_FORMAT_R8G8B8_UNORM;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ fmt = PIPE_FORMAT_B5G6R5_UNORM;
+ break;
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_5551:
+ case HAL_PIXEL_FORMAT_RGBA_4444:
+ default:
+ fmt = PIPE_FORMAT_NONE;
+ break;
+ }
+
+ return fmt;
+}
+
+static unsigned
+get_pipe_bind(int usage)
+{
+ unsigned bind = PIPE_BIND_SHARED;
+
+ if (usage & GRALLOC_USAGE_SW_READ_MASK)
+ bind |= PIPE_BIND_TRANSFER_READ;
+ if (usage & GRALLOC_USAGE_SW_WRITE_MASK)
+ bind |= PIPE_BIND_TRANSFER_WRITE;
+
+ if (usage & GRALLOC_USAGE_HW_TEXTURE)
+ bind |= PIPE_BIND_SAMPLER_VIEW;
+ if (usage & GRALLOC_USAGE_HW_RENDER)
+ bind |= PIPE_BIND_RENDER_TARGET;
+ if (usage & GRALLOC_USAGE_HW_FB) {
+ bind |= PIPE_BIND_RENDER_TARGET;
+ bind |= PIPE_BIND_SCANOUT;
+ }
+
+ return bind;
+}
+
+static struct drm_pipe_buffer *
+get_pipe_buffer(struct drm_pipe_manager *pm, int width, int height,
+ int format, int usage, struct winsys_handle *winsys)
+{
+ struct drm_pipe_buffer *buf;
+ struct pipe_resource templ;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.format = get_pipe_format(format);
+ templ.bind = get_pipe_bind(usage);
+ templ.target = PIPE_TEXTURE_2D;
+
+ if (templ.format == PIPE_FORMAT_NONE ||
+ !pm->screen->is_format_supported(pm->screen, templ.format,
+ templ.target, 0, templ.bind, 0)) {
+ LOGE("unsupported format 0x%x", format);
+ return NULL;
+ }
+
+ buf = CALLOC(1, sizeof(*buf));
+ if (!buf)
+ return NULL;
+
+ templ.width0 = width;
+ templ.height0 = height;
+ templ.depth0 = 1;
+
+ if (winsys) {
+ buf->resource = pm->screen->resource_from_handle(pm->screen,
+ &templ, winsys);
+ if (!buf->resource)
+ goto fail;
+
+ buf->winsys = *winsys;
+ }
+ else {
+ buf->resource = pm->screen->resource_create(pm->screen, &templ);
+ if (!buf->resource)
+ goto fail;
+
+ buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED;
+ if (!pm->screen->resource_get_handle(pm->screen, buf->resource, &buf->winsys))
+ goto fail;
+ }
+
+ /* need the gem handle for fb */
+ if (usage & GRALLOC_USAGE_HW_FB) {
+ struct winsys_handle tmp;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = DRM_API_HANDLE_TYPE_KMS;
+ if (!pm->screen->resource_get_handle(pm->screen, buf->resource, &tmp))
+ goto fail;
+
+ buf->fb_handle = tmp.handle;
+ }
+
+ return buf;
+
+fail:
+ LOGE("failed to allocate pipe buffer");
+ if (buf->resource)
+ pipe_resource_reference(&buf->resource, NULL);
+ FREE(buf);
+
+ return NULL;
+}
+
+struct drm_bo_t *
+drm_gem_drv_alloc(struct drm_module_t *drm, int width, int height,
+ int format, int usage, int *stride)
+{
+ struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem;
+ struct drm_pipe_buffer *buf;
+ struct drm_bo_t *bo;
+ struct pipe_resource templ;
+
+ bo = drm_gem_create_bo(width, height, format, usage);
+ if (!bo)
+ return NULL;
+
+ pthread_mutex_lock(&pm->mutex);
+ buf = get_pipe_buffer(pm, width, height, format, usage, NULL);
+ pthread_mutex_unlock(&pm->mutex);
+
+ if (buf) {
+ bo->name = (int) buf->winsys.handle;
+ bo->stride = (int) buf->winsys.stride;
+
+ bo->fb_handle = buf->fb_handle;
+ bo->data = (int) buf;
+
+ *stride = bo->stride;
+ }
+ else {
+ free(bo);
+ bo = NULL;
+ }
+
+ return bo;
+}
+
+void
+drm_gem_drv_free(struct drm_module_t *drm, struct drm_bo_t *bo)
+{
+ struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem;
+ struct drm_pipe_buffer *buf = (struct drm_pipe_buffer *) bo->data;
+
+ pthread_mutex_lock(&pm->mutex);
+
+ if (buf->transfer)
+ pipe_transfer_destroy(pm->context, buf->transfer);
+ pipe_resource_reference(&buf->resource, NULL);
+
+ pthread_mutex_unlock(&pm->mutex);
+
+ FREE(buf);
+ free(bo);
+}
+
+int
+drm_gem_drv_map(struct drm_module_t *drm, struct drm_bo_t *bo,
+ int x, int y, int w, int h, int enable_write, void **addr)
+{
+ struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem;
+ struct drm_pipe_buffer *buf = (struct drm_pipe_buffer *) bo->data;
+ enum pipe_transfer_usage usage = 0;
+ int ret = 0;
+
+ pthread_mutex_lock(&pm->mutex);
+
+ /* need a context to get transfer */
+ if (!pm->context) {
+ pm->context = pm->screen->context_create(pm->screen, NULL);
+ if (!pm->context) {
+ LOGE("failed to create pipe context");
+ ret = -ENOMEM;
+ }
+ }
+
+ /* the bo was allocated by another process */
+ if (!buf && !ret) {
+ struct winsys_handle winsys;
+
+ memset(&winsys, 0, sizeof(winsys));
+ winsys.type = DRM_API_HANDLE_TYPE_SHARED;
+ winsys.handle = bo->name;
+ winsys.stride = bo->stride;
+
+ buf = get_pipe_buffer(pm, bo->width, bo->height,
+ bo->format, bo->usage, &winsys);
+ if (!buf) {
+ LOGE("failed to create pipe buffer from name %u", bo->name);
+ ret = -ENOMEM;
+ }
+
+ bo->data = (int) buf;
+ }
+
+ if (buf) {
+ usage = PIPE_TRANSFER_READ;
+ if (enable_write)
+ usage |= PIPE_TRANSFER_WRITE;
+
+ assert(!buf->transfer);
+
+ /*
+ * ignore x, y, w and h so that returned addr points at the start of the
+ * buffer
+ */
+ buf->transfer = pipe_get_transfer(pm->context, buf->resource,
+ 0, 0, usage, 0, 0, bo->width, bo->height);
+ if (buf->transfer)
+ *addr = pipe_transfer_map(pm->context, buf->transfer);
+ else
+ ret = -ENOMEM;
+ }
+
+ pthread_mutex_unlock(&pm->mutex);
+
+ return ret;
+}
+
+void
+drm_gem_drv_unmap(struct drm_module_t *drm, struct drm_bo_t *bo)
+{
+ struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem;
+ struct drm_pipe_buffer *buf = (struct drm_pipe_buffer *) bo->data;
+
+ pthread_mutex_lock(&pm->mutex);
+
+ assert(buf && buf->transfer);
+
+ pipe_transfer_unmap(pm->context, buf->transfer);
+ pipe_transfer_destroy(pm->context, buf->transfer);
+ buf->transfer = NULL;
+
+ pm->context->flush(pm->context, PIPE_FLUSH_RENDER_CACHE, NULL);
+
+ pthread_mutex_unlock(&pm->mutex);
+}
diff --git a/src/gralloc/gralloc_kms.c b/src/gralloc/gralloc_kms.c
new file mode 100644
index 0000000000..569e862f9b
--- /dev/null
+++ b/src/gralloc/gralloc_kms.c
@@ -0,0 +1,243 @@
+#define LOG_TAG "GRALLOC-KMS"
+
+#include <cutils/log.h>
+#include <errno.h>
+#include <unistd.h>
+#include "gralloc_kms.h"
+
+int
+drm_kms_add_fb(struct drm_module_t *drm, struct drm_bo_t *bo)
+{
+ uint8_t bpp;
+
+ bpp = drm_mod_get_bpp(bo->format) * 8;
+
+ return drmModeAddFB(drm->fd, bo->width, bo->height, bpp, bpp,
+ bo->stride, bo->fb_handle, (uint32_t *) &bo->fb_id);
+}
+
+void
+drm_kms_rm_fb(struct drm_module_t *drm, struct drm_bo_t *bo)
+{
+ drmModeRmFB(drm->fd, bo->fb_id);
+ bo->fb_id = 0;
+}
+
+static void
+drm_kms_wait_vblank(struct drm_module_t *drm, int num)
+{
+ drmVBlank vbl;
+ int ret;
+
+ memset(&vbl, 0, sizeof(vbl));
+ vbl.request.type = DRM_VBLANK_RELATIVE;
+ if (drm->vblank_secondary)
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ vbl.request.sequence = num;
+
+ ret = drmWaitVBlank(drm->fd, &vbl);
+ if (ret)
+ LOGW("failed to wait vblank");
+}
+
+static int
+drm_kms_set_crtc(struct drm_module_t *drm, struct drm_bo_t *bo)
+{
+ int ret;
+
+ if (drm->swap_interval)
+ drm_kms_wait_vblank(drm, drm->swap_interval);
+
+ ret = drmModeSetCrtc(drm->fd, drm->crtc_id, bo->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, bo->fb_id, &drm->clip, 1);
+#endif
+
+ return ret;
+}
+
+static int
+drm_kms_page_flip(struct drm_module_t *drm, struct drm_bo_t *bo)
+{
+ int waits = 3, ret;
+
+ if (drm->swap_interval > 1)
+ drm_kms_wait_vblank(drm, drm->swap_interval - 1);
+
+ while (waits) {
+ ret = drmModePageFlip(drm->fd, drm->crtc_id, bo->fb_id, 0x0, NULL);
+ if (ret && errno == -EBUSY) {
+ if (drm->swap_interval)
+ drm_kms_wait_vblank(drm, 1);
+ else
+ usleep(5000);
+ waits--;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (ret)
+ LOGE("failed to perform page flip");
+
+ return ret;
+}
+
+int
+drm_kms_post(struct drm_module_t *drm, struct drm_bo_t *bo)
+{
+ int ret;
+
+ if (!bo->fb_id) {
+ LOGE("unable to post bo %p without fb", bo);
+ return -EINVAL;
+ }
+
+ /* TODO spawn a thread to avoid waiting */
+
+ if (drm->first_post) {
+ pthread_mutex_lock(&drm->mutex);
+ if (drm->first_post) {
+ ret = drm_kms_set_crtc(drm, bo);
+ if (!ret)
+ drm->first_post = 0;
+ pthread_mutex_unlock(&drm->mutex);
+
+ return ret;
+ }
+ pthread_mutex_unlock(&drm->mutex);
+ }
+
+ if (drm->mode_page_flip && drm->swap_interval)
+ ret = drm_kms_page_flip(drm, bo);
+ else
+ ret = drm_kms_set_crtc(drm, bo);
+
+ return ret;
+}
+
+static int
+drm_kms_init_with_connector_locked(struct drm_module_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
+
+ drm->first_post = 1;
+
+ return 0;
+}
+
+static int
+drm_kms_init_locked(struct drm_module_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;
+ }
+
+ 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_locked(drm, connector))
+ break;
+ }
+
+ drmModeFreeConnector(connector);
+ }
+ }
+ if (i == drm->resources->count_connectors) {
+ drmModeFreeResources(drm->resources);
+ drm->resources = NULL;
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int
+drm_kms_init(struct drm_module_t *drm)
+{
+ int ret;
+
+ pthread_mutex_lock(&drm->mutex);
+ ret = drm_kms_init_locked(drm);
+ pthread_mutex_unlock(&drm->mutex);
+
+ return ret;
+}
diff --git a/src/gralloc/gralloc_kms.h b/src/gralloc/gralloc_kms.h
new file mode 100644
index 0000000000..44708e0034
--- /dev/null
+++ b/src/gralloc/gralloc_kms.h
@@ -0,0 +1,19 @@
+#ifndef _DRM_KMS_H_
+#define _DRM_KMS_H_
+
+#include "gralloc_mod.h"
+#include "gralloc_gem.h"
+
+int
+drm_kms_init(struct drm_module_t *drm);
+
+int
+drm_kms_add_fb(struct drm_module_t *drm, struct drm_bo_t *bo);
+
+void
+drm_kms_rm_fb(struct drm_module_t *drm, struct drm_bo_t *bo);
+
+int
+drm_kms_post(struct drm_module_t *drm, struct drm_bo_t *bo);
+
+#endif /* _DRM_KMS_H_ */
diff --git a/src/gralloc/gralloc_mod.c b/src/gralloc/gralloc_mod.c
new file mode 100644
index 0000000000..1296d2af04
--- /dev/null
+++ b/src/gralloc/gralloc_mod.c
@@ -0,0 +1,328 @@
+#define LOG_TAG "GRALLOC-MOD"
+
+#include <cutils/log.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "gralloc_mod.h"
+#include "gralloc_gem.h"
+#include "gralloc_kms.h"
+
+static int
+drm_mod_perform(const struct gralloc_module_t *mod, int op, ...)
+{
+ struct drm_module_t *drm = (struct drm_module_t *) mod;
+ va_list args;
+ int ret;
+
+ va_start(args, op);
+ switch (op) {
+ case GRALLOC_MODULE_PERFORM_GET_DRM_FD:
+ {
+ int *fd = va_arg(args, int *);
+
+ ret = drm_gem_init(drm);
+ if (!ret)
+ *fd = drm->fd;
+ }
+ break;
+ case GRALLOC_MODULE_PERFORM_GET_DRM_MAGIC:
+ {
+ int32_t *magic = va_arg(args, int32_t *);
+
+ ret = drm_gem_init(drm);
+ if (!ret)
+ ret = drm_gem_get_magic(drm, magic);
+ }
+ break;
+ case GRALLOC_MODULE_PERFORM_AUTH_DRM_MAGIC:
+ {
+ int32_t magic = va_arg(args, int32_t);
+
+ ret = drm_gem_init(drm);
+ if (!ret)
+ ret = drm_gem_auth_magic(drm, magic);
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ va_end(args);
+
+ return ret;
+}
+
+static int
+drm_mod_register_buffer(const gralloc_module_t *mod, buffer_handle_t handle)
+{
+ return (drm_gem_get(handle)) ? 0 : -EINVAL;
+}
+
+static int
+drm_mod_unregister_buffer(const gralloc_module_t *mod, buffer_handle_t handle)
+{
+ return (drm_gem_get(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 *drm = (struct drm_module_t *) mod;
+ struct drm_bo_t *bo;
+ int ret;
+
+ ret = drm_gem_init(drm);
+ if (!ret)
+ ret = drm_gem_drv_init(drm);
+ if (ret)
+ return ret;
+
+ bo = drm_gem_validate(handle);
+ if (!bo)
+ return -EINVAL;
+
+ return drm_gem_drv_map(drm, 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 *drm = (struct drm_module_t *) mod;
+ struct drm_bo_t *bo;
+
+ bo = drm_gem_validate(handle);
+ if (!bo)
+ return -EINVAL;
+
+ drm_gem_drv_unmap(drm, 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 *drm = (struct drm_module_t *) dev->common.module;
+ struct drm_bo_t *bo;
+
+ bo = drm_gem_validate(handle);
+ if (!bo)
+ return -EINVAL;
+
+ if (bo->usage & GRALLOC_USAGE_HW_FB)
+ drm_kms_rm_fb(drm, bo);
+
+ drm_gem_drv_free(drm, 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 *drm = (struct drm_module_t *) dev->common.module;
+ struct drm_bo_t *bo;
+ int size, bpp, ret;
+
+ ret = drm_gem_drv_init(drm);
+ if (ret)
+ return ret;
+
+ bpp = drm_mod_get_bpp(format);
+ if (!bpp)
+ return -EINVAL;
+
+ bo = drm_gem_drv_alloc(drm, w, h, format, usage, stride);
+ if (!bo)
+ return -EINVAL;
+ if (bo->usage & GRALLOC_USAGE_HW_FB) {
+ ret = drm_kms_add_fb(drm, bo);
+ if (ret) {
+ LOGE("failed to add fb");
+ drm_gem_drv_free(drm, bo);
+ return ret;
+ }
+ }
+
+ *stride /= bpp;
+ *handle = &bo->base;
+
+ return 0;
+}
+
+static int
+drm_mod_open_gpu0(struct drm_module_t *drm, hw_device_t **dev)
+{
+ struct alloc_device_t *alloc;
+ int ret;
+
+ ret = drm_gem_init(drm);
+ if (ret)
+ return ret;
+
+ alloc = calloc(1, sizeof(*alloc));
+ if (!alloc)
+ return -EINVAL;
+
+ alloc->common.tag = HARDWARE_DEVICE_TAG;
+ alloc->common.version = 0;
+ alloc->common.module = (hw_module_t *) drm;
+ 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 *drm = (struct drm_module_t *) fb->common.module;
+ struct drm_bo_t *bo;
+
+ bo = drm_gem_validate(handle);
+ if (!bo)
+ return -EINVAL;
+
+ return drm_kms_post(drm, bo);
+}
+
+#include <EGL/egl.h>
+static int
+drm_mod_composition_complete_fb0(struct framebuffer_device_t *fb)
+{
+ eglWaitClient();
+ return 0;
+}
+
+static int
+drm_mod_open_fb0(struct drm_module_t *drm, struct hw_device_t **dev)
+{
+ struct framebuffer_device_t *fb;
+ int ret;
+
+ fb = calloc(1, sizeof(*fb));
+ if (!fb)
+ return -ENOMEM;
+
+ ret = drm_gem_init(drm);
+ if (!ret)
+ ret = drm_kms_init(drm);
+ if (ret) {
+ free(fb);
+ return ret;
+ }
+
+ fb->common.tag = HARDWARE_DEVICE_TAG;
+ fb->common.version = 0;
+ fb->common.module = (hw_module_t *) drm;
+ 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;
+
+ *((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;
+
+ *dev = &fb->common;
+
+ LOGI("mode.hdisplay %d\n"
+ "mode.vdisplay %d\n"
+ "mode.vrefresh %d\n"
+ "format 0x%x\n"
+ "xdpi %d\n"
+ "ydpi %d\n",
+ drm->mode.hdisplay,
+ drm->mode.vdisplay,
+ drm->mode.vrefresh,
+ drm->format,
+ drm->xdpi, drm->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 *drm = (struct drm_module_t *) mod;
+ int ret;
+
+ if (strcmp(name, GRALLOC_HARDWARE_GPU0) == 0)
+ ret = drm_mod_open_gpu0(drm, dev);
+ else if (strcmp(name, GRALLOC_HARDWARE_FB0) == 0)
+ ret = drm_mod_open_fb0(drm, dev);
+ else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+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,
+ .fd = -1
+};
diff --git a/src/gralloc/gralloc_mod.h b/src/gralloc/gralloc_mod.h
new file mode 100644
index 0000000000..e06ec864ad
--- /dev/null
+++ b/src/gralloc/gralloc_mod.h
@@ -0,0 +1,65 @@
+#ifndef _GRALLOC_DRM_H
+#define _GRALLOC_DRM_H
+
+#include <hardware/gralloc.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <pthread.h>
+
+struct drm_module_t {
+ gralloc_module_t base;
+
+ pthread_mutex_t mutex;
+
+ /* initialized by drm_gem_init */
+ int fd;
+
+ /* initialized by drm_kms_init */
+ 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
+
+ /* initialized by drm_gem_drv_init */
+ void *gem;
+ int mode_dirty_fb;
+ int mode_page_flip;
+ int swap_interval;
+ int vblank_secondary;
+
+ int first_post;
+};
+
+static inline int
+drm_mod_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;
+}
+
+#endif /* _GRALLOC_DRM_H */