OSDN Git Service

android: Add DRM-based gralloc.
authorChia-I Wu <olv@lunarg.com>
Mon, 11 Oct 2010 08:06:47 +0000 (16:06 +0800)
committerChia-I Wu <olvaffe@gmail.com>
Fri, 10 Dec 2010 01:01:35 +0000 (20:01 -0500)
src/gralloc/gralloc_gem.c [new file with mode: 0644]
src/gralloc/gralloc_gem.h [new file with mode: 0644]
src/gralloc/gralloc_gem_i915.c [new file with mode: 0644]
src/gralloc/gralloc_gem_pipe.c [new file with mode: 0644]
src/gralloc/gralloc_kms.c [new file with mode: 0644]
src/gralloc/gralloc_kms.h [new file with mode: 0644]
src/gralloc/gralloc_mod.c [new file with mode: 0644]
src/gralloc/gralloc_mod.h [new file with mode: 0644]

diff --git a/src/gralloc/gralloc_gem.c b/src/gralloc/gralloc_gem.c
new file mode 100644 (file)
index 0000000..a3df97f
--- /dev/null
@@ -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 (file)
index 0000000..e6ef176
--- /dev/null
@@ -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 (file)
index 0000000..2822fe5
--- /dev/null
@@ -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 (file)
index 0000000..99a8461
--- /dev/null
@@ -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 (file)
index 0000000..6ae9446
--- /dev/null
@@ -0,0 +1,241 @@
+#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)
+      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 (file)
index 0000000..44708e0
--- /dev/null
@@ -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 (file)
index 0000000..1296d2a
--- /dev/null
@@ -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 (file)
index 0000000..e06ec86
--- /dev/null
@@ -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 */