summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2011-05-26 15:11:50 +0200
committerBenjamin Franzke <benjaminfranzke@googlemail.com>2011-05-30 14:37:19 +0200
commit790a4793c496af39fe00a203ea67ddaef607ad1a (patch)
treecf38500d4deab64ca87a55ed30a06a968dcd6aab
parent621d36fe4f6b6effc9bf3bf15eeeaa611b1faccb (diff)
gbm: Add gallium (drm) backend
-rw-r--r--configure.ac15
-rw-r--r--src/gallium/state_trackers/gbm/Makefile46
-rw-r--r--src/gallium/state_trackers/gbm/gbm_g3d_drm.c209
-rw-r--r--src/gallium/state_trackers/gbm/gbm_gallium_drmint.h51
-rw-r--r--src/gallium/targets/gbm/.gitignore1
-rw-r--r--src/gallium/targets/gbm/Makefile41
l---------src/gallium/targets/gbm/extract_pci_list.sh1
-rw-r--r--src/gallium/targets/gbm/gbm.c172
-rw-r--r--src/gallium/targets/gbm/pci_list.c74
9 files changed, 610 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 872ab1ac0e..568700ed0d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1550,6 +1550,11 @@ yes)
HAVE_ST_EGL="yes"
fi
fi
+
+ if test "x$enable_gbm" = xyes; then
+ HAVE_ST_GBM="yes"
+ GALLIUM_STATE_TRACKERS_DIRS="$GALLIUM_STATE_TRACKERS_DIRS gbm"
+ fi
;;
*)
# verify the requested state tracker exist
@@ -1569,6 +1574,12 @@ yes)
fi
HAVE_ST_EGL="yes"
;;
+ gbm)
+ if test "x$enable_gbm" != xyes; then
+ AC_MSG_ERROR([cannot build gbm state tracker without gbm library])
+ fi
+ HAVE_ST_GBM="yes"
+ ;;
xorg)
PKG_CHECK_MODULES([XORG], [xorg-server >= 1.6.0])
PKG_CHECK_MODULES([LIBDRM_XORG], [libdrm >= $LIBDRM_XORG_REQUIRED])
@@ -1626,6 +1637,10 @@ if test "x$HAVE_ST_EGL" = xyes; then
GALLIUM_TARGET_DIRS="$GALLIUM_TARGET_DIRS egl"
fi
+if test "x$HAVE_ST_GBM" = xyes; then
+ GALLIUM_TARGET_DIRS="$GALLIUM_TARGET_DIRS gbm"
+fi
+
if test "x$HAVE_ST_XORG" = xyes; then
PKG_CHECK_MODULES(XEXT, [xextproto >= 7.0.99.1],
HAVE_XEXTPROTO_71="yes"; DEFINES="$DEFINES -DHAVE_XEXTPROTO_71",
diff --git a/src/gallium/state_trackers/gbm/Makefile b/src/gallium/state_trackers/gbm/Makefile
new file mode 100644
index 0000000000..a4ccf63a4b
--- /dev/null
+++ b/src/gallium/state_trackers/gbm/Makefile
@@ -0,0 +1,46 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+common_INCLUDES = \
+ -I. \
+ -I$(TOP)/src/gallium/include \
+ -I$(TOP)/src/gallium/auxiliary \
+ -I$(TOP)/src/gbm/main \
+ -I$(TOP)/include
+
+common_SOURCES = $(wildcard *.c)
+common_OBJECTS = $(common_SOURCES:.c=.o)
+
+ALL_INCLUDES = $(common_INCLUDES)
+ALL_SOURCES = $(common_SOURCES)
+
+GBM_OBJECTS = $(common_OBJECTS)
+GBM_CPPFLAGS = $(common_INCLUDES)
+
+##### TARGETS #####
+
+default: depend libgbm.a
+
+libgbm.a: $(GBM_OBJECTS) Makefile
+ $(MKLIB) -o gbm -static $(GBM_OBJECTS)
+
+depend:
+ rm -f depend
+ touch depend
+ $(MKDEP) $(MKDEP_OPTIONS) $(ALL_INCLUDES) $(ALL_SOURCES) 2> /dev/null
+
+clean:
+ rm -f libgbm.a
+ rm -f $(GBM_OBJECTS)
+ rm -f depend depend.bak
+
+# Dummy target
+install:
+ @echo -n ""
+
+##### RULES #####
+
+$(common_OBJECTS): %.o: %.c
+ $(CC) -c $(GBM_CPPFLAGS) $(DEFINES) $(CFLAGS) $< -o $@
+
+sinclude depend
diff --git a/src/gallium/state_trackers/gbm/gbm_g3d_drm.c b/src/gallium/state_trackers/gbm/gbm_g3d_drm.c
new file mode 100644
index 0000000000..b98f95c3aa
--- /dev/null
+++ b/src/gallium/state_trackers/gbm/gbm_g3d_drm.c
@@ -0,0 +1,209 @@
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+
+#include "state_tracker/drm_driver.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "gbm_gallium_drmint.h"
+
+static INLINE enum pipe_format
+gbm_format_to_gallium(enum gbm_bo_format format)
+{
+ switch (format) {
+ case GBM_BO_FORMAT_XRGB8888:
+ return PIPE_FORMAT_B8G8R8X8_UNORM;
+ case GBM_BO_FORMAT_ARGB8888:
+ return PIPE_FORMAT_B8G8R8A8_UNORM;
+ default:
+ return PIPE_FORMAT_NONE;
+ }
+
+ return PIPE_FORMAT_NONE;
+}
+
+static INLINE uint
+gbm_usage_to_gallium(uint usage)
+{
+ uint resource_usage = 0;
+
+ if (usage & GBM_BO_USE_SCANOUT)
+ resource_usage |= PIPE_BIND_SCANOUT;
+
+ if (usage & GBM_BO_USE_RENDERING)
+ resource_usage |= PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
+
+#if 0
+ if (usage & GBM_BO_USE_CURSOR_64X64)
+ resource_usage |= PIPE_BIND_CURSOR;
+#endif
+
+ return resource_usage;
+}
+
+static int
+gbm_gallium_drm_is_format_supported(struct gbm_device *gbm,
+ enum gbm_bo_format format,
+ uint32_t usage)
+{
+ struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
+ enum pipe_format pf;
+
+ pf = gbm_format_to_gallium(format);
+ if (pf == PIPE_FORMAT_NONE)
+ return 0;
+
+ if (!gdrm->screen->is_format_supported(gdrm->screen, PIPE_TEXTURE_2D, pf, 0,
+ gbm_usage_to_gallium(usage)))
+ return 0;
+
+ if (usage & GBM_BO_USE_SCANOUT && format != GBM_BO_FORMAT_XRGB8888)
+ return 0;
+
+ return 1;
+}
+
+static void
+gbm_gallium_drm_bo_destroy(struct gbm_bo *_bo)
+{
+ struct gbm_gallium_drm_bo *bo = gbm_gallium_drm_bo(_bo);
+
+ pipe_resource_reference(&bo->resource, NULL);
+ free(bo);
+}
+
+static struct gbm_bo *
+gbm_gallium_drm_bo_create_from_egl_image(struct gbm_device *gbm,
+ void *egl_dpy, void *egl_image,
+ uint32_t width, uint32_t height)
+{
+ struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
+ struct gbm_gallium_drm_bo *bo;
+ struct winsys_handle whandle;
+
+ if (!gdrm->lookup_egl_image)
+ return NULL;
+
+ bo = CALLOC_STRUCT(gbm_gallium_drm_bo);
+ if (bo == NULL)
+ return NULL;
+
+ bo->resource = gdrm->lookup_egl_image(gdrm->lookup_egl_image_data,
+ egl_image);
+ if (bo->resource == NULL) {
+ FREE(bo);
+ return NULL;
+ }
+
+ bo->base.base.gbm = gbm;
+ bo->base.base.width = width;
+ bo->base.base.height = height;
+
+ memset(&whandle, 0, sizeof(whandle));
+ whandle.type = DRM_API_HANDLE_TYPE_KMS;
+ gdrm->screen->resource_get_handle(gdrm->screen, bo->resource, &whandle);
+
+ bo->base.base.handle.u32 = whandle.handle;
+ bo->base.base.pitch = whandle.stride;
+
+ return &bo->base.base;
+}
+
+static struct gbm_bo *
+gbm_gallium_drm_bo_create(struct gbm_device *gbm,
+ uint32_t width, uint32_t height,
+ enum gbm_bo_format format, uint32_t usage)
+{
+ struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
+ struct gbm_gallium_drm_bo *bo;
+ struct pipe_resource templ;
+ struct winsys_handle whandle;
+ enum pipe_format pf;
+
+ bo = CALLOC_STRUCT(gbm_gallium_drm_bo);
+ if (bo == NULL)
+ return NULL;
+
+ bo->base.base.gbm = gbm;
+ bo->base.base.width = width;
+ bo->base.base.height = height;
+
+ pf = gbm_format_to_gallium(format);
+ if (pf == PIPE_FORMAT_NONE)
+ return NULL;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.bind = gbm_usage_to_gallium(usage);
+ templ.format = pf;
+ templ.target = PIPE_TEXTURE_2D;
+ templ.last_level = 0;
+ templ.width0 = width;
+ templ.height0 = height;
+ templ.depth0 = 1;
+ templ.array_size = 1;
+
+ bo->resource = gdrm->screen->resource_create(gdrm->screen, &templ);
+ if (bo->resource == NULL) {
+ FREE(bo);
+ return NULL;
+ }
+
+ memset(&whandle, 0, sizeof(whandle));
+ whandle.type = DRM_API_HANDLE_TYPE_KMS;
+ gdrm->screen->resource_get_handle(gdrm->screen, bo->resource, &whandle);
+
+ bo->base.base.handle.u32 = whandle.handle;
+ bo->base.base.pitch = whandle.stride;
+
+ return &bo->base.base;
+}
+
+static boolean
+pipe_modules_destroy(void)
+{
+ //util_dl_close
+
+ return TRUE;
+}
+
+static void
+gbm_gallium_drm_destroy(struct gbm_device *gbm)
+{
+ struct gbm_gallium_drm_device *gdrm = gbm_gallium_drm_device(gbm);
+
+ gdrm->screen->destroy(gdrm->screen);
+
+ pipe_modules_destroy();
+ FREE(gdrm->base.driver_name);
+
+ FREE(gdrm);
+}
+
+struct gbm_device *
+gbm_gallium_drm_device_create(int fd)
+{
+ struct gbm_gallium_drm_device *gdrm;
+ int ret;
+
+ gdrm = calloc(1, sizeof *gdrm);
+
+ gdrm->base.base.fd = fd;
+ gdrm->base.base.bo_create = gbm_gallium_drm_bo_create;
+ gdrm->base.base.bo_create_from_egl_image =
+ gbm_gallium_drm_bo_create_from_egl_image;
+ gdrm->base.base.bo_destroy = gbm_gallium_drm_bo_destroy;
+ gdrm->base.base.is_format_supported = gbm_gallium_drm_is_format_supported;
+ gdrm->base.base.destroy = gbm_gallium_drm_destroy;
+
+ gdrm->base.type = GBM_DRM_DRIVER_TYPE_GALLIUM;
+ gdrm->base.base.name = "drm";
+
+ ret = gallium_screen_create(gdrm);
+ if (ret) {
+ free(gdrm);
+ return NULL;
+ }
+
+ return &gdrm->base.base;
+}
diff --git a/src/gallium/state_trackers/gbm/gbm_gallium_drmint.h b/src/gallium/state_trackers/gbm/gbm_gallium_drmint.h
new file mode 100644
index 0000000000..30031780e9
--- /dev/null
+++ b/src/gallium/state_trackers/gbm/gbm_gallium_drmint.h
@@ -0,0 +1,51 @@
+
+#ifndef _GBM_GALLIUM_DRM_INTERNAL_H_
+#define _GBM_GALLIUM_DRM_INTERNAL_H_
+
+#include "pipe/p_state.h"
+
+#include "gbmint.h"
+
+#include "common.h"
+#include "common_drm.h"
+
+struct gbm_gallium_drm_device {
+ struct gbm_drm_device base;
+
+ struct pipe_screen *screen;
+ void *driver;
+
+ struct pipe_resource *(*lookup_egl_image)(void *data,
+ void *egl_image);
+ void *lookup_egl_image_data;
+
+};
+
+struct gbm_gallium_drm_bo {
+ struct gbm_drm_bo base;
+
+ struct pipe_resource *resource;
+};
+
+static inline struct gbm_gallium_drm_device *
+gbm_gallium_drm_device(struct gbm_device *gbm)
+{
+ return (struct gbm_gallium_drm_device *) gbm;
+}
+
+static inline struct gbm_gallium_drm_bo *
+gbm_gallium_drm_bo(struct gbm_bo *bo)
+{
+ return (struct gbm_gallium_drm_bo *) bo;
+}
+
+char *
+util_drm_fd_get_screen_name(int fd);
+
+struct gbm_device *
+gbm_gallium_drm_device_create(int fd);
+
+int
+gallium_screen_create(struct gbm_gallium_drm_device *gdrm);
+
+#endif
diff --git a/src/gallium/targets/gbm/.gitignore b/src/gallium/targets/gbm/.gitignore
new file mode 100644
index 0000000000..b41bd4cc62
--- /dev/null
+++ b/src/gallium/targets/gbm/.gitignore
@@ -0,0 +1 @@
+pci_list.h
diff --git a/src/gallium/targets/gbm/Makefile b/src/gallium/targets/gbm/Makefile
new file mode 100644
index 0000000000..3ae4f29ad1
--- /dev/null
+++ b/src/gallium/targets/gbm/Makefile
@@ -0,0 +1,41 @@
+# src/gallium/targets/gbm/Makefile
+
+TOP = ../../../..
+include $(TOP)/configs/current
+
+PIPE_PREFIX := pipe_
+
+GBM_BACKEND = gbm_gallium_drm
+GBM_SOURCES = gbm.c pci_list.o
+
+GBM_INCLUDES = \
+ -I$(TOP)/include \
+ -I$(TOP)/src/gallium/state_trackers/gbm \
+ -I$(TOP)/src/gbm/main \
+ -I$(TOP)/src/gallium/auxiliary \
+ -I$(TOP)/src/gallium/include \
+
+GBM_LIBS = $(LIBUDEV_LIBS) $(LIBDRM_LIB) \
+ $(TOP)/src/gallium/state_trackers/gbm/libgbm.a \
+ $(TOP)/src/gallium/drivers/identity/libidentity.a \
+ $(TOP)/src/gallium/drivers/trace/libtrace.a \
+ $(TOP)/src/gallium/drivers/rbug/librbug.a \
+ $(GALLIUM_AUXILIARIES)
+
+
+GBM_CFLAGS = \
+ -D_EGL_GALLIUM_DRIVER_SEARCH_DIR=\"$(EGL_DRIVER_INSTALL_DIR)\" \
+ -DPIPE_PREFIX=\"$(PIPE_PREFIX)\" \
+ $(LIBUDEV_CFLAGS) \
+ $(LIBDRM_CFLAGS)
+
+include $(TOP)/src/gbm/backends/Makefile.template
+
+pci_list.h: $(DRIVER_PCI_LISTS) ./extract_pci_list.sh
+ `cat $(DRIVER_PCI_LISTS) | ./extract_pci_list.sh chip_ids > $@`
+ `cat $(DRIVER_PCI_LISTS) | ./extract_pci_list.sh driver_map >> $@`
+
+pci_list.o: pci_list.h
+
+clean::
+ rm -f pci_list.h
diff --git a/src/gallium/targets/gbm/extract_pci_list.sh b/src/gallium/targets/gbm/extract_pci_list.sh
new file mode 120000
index 0000000000..f1386ff00b
--- /dev/null
+++ b/src/gallium/targets/gbm/extract_pci_list.sh
@@ -0,0 +1 @@
+../../../gbm/extract_pci_list.sh \ No newline at end of file
diff --git a/src/gallium/targets/gbm/gbm.c b/src/gallium/targets/gbm/gbm.c
new file mode 100644
index 0000000000..02f15a99c2
--- /dev/null
+++ b/src/gallium/targets/gbm/gbm.c
@@ -0,0 +1,172 @@
+#include <limits.h>
+
+#include "util/u_memory.h"
+#include "util/u_string.h"
+#include "util/u_dl.h"
+#include "util/u_inlines.h"
+
+#include "state_tracker/drm_driver.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "gbm_gallium_drmint.h"
+
+static struct pipe_module {
+ boolean initialized;
+ char *name;
+ struct util_dl_library *lib;
+ const struct drm_driver_descriptor *drmdd;
+} pipe_modules[16];
+
+static char *
+loader_strdup(const char *s)
+{
+ size_t len = (s) ? strlen(s) : 0;
+ char *t = MALLOC(len + 1);
+ if (t) {
+ memcpy(t, s, len);
+ t[len] = '\0';
+ }
+ return t;
+}
+
+static void
+find_pipe_module(struct pipe_module *pmod, const char *name)
+{
+ char *search_paths, *end, *next, *p;
+ char path[PATH_MAX];
+ int ret;
+
+ search_paths = NULL;
+ if (geteuid() == getuid()) {
+ /* don't allow setuid apps to use EGL_DRIVERS_PATH */
+ search_paths = getenv("EGL_DRIVERS_PATH");
+ }
+ if (search_paths == NULL)
+ search_paths = _EGL_GALLIUM_DRIVER_SEARCH_DIR;
+
+ end = search_paths + strlen(search_paths);
+ for (p = search_paths; p < end && pmod->lib == NULL; p = next + 1) {
+ int len;
+ next = strchr(p, ':');
+ if (next == NULL)
+ next = end;
+
+ len = next - p;
+
+ if (len) {
+ ret = util_snprintf(path, sizeof(path),
+ "%.*s/" PIPE_PREFIX "%s" UTIL_DL_EXT, len, p, pmod->name);
+ }
+ else {
+ ret = util_snprintf(path, sizeof(path),
+ PIPE_PREFIX "%s" UTIL_DL_EXT, pmod->name);
+ }
+ if (ret > 0 && ret < sizeof(path)) {
+ pmod->lib = util_dl_open(path);
+ debug_printf("loaded %s\n", path);
+ }
+
+ }
+}
+
+static boolean
+load_pipe_module(struct pipe_module *pmod, const char *name)
+{
+ pmod->name = loader_strdup(name);
+ if (!pmod->name)
+ return FALSE;
+
+ find_pipe_module(pmod, name);
+
+ if (pmod->lib) {
+ pmod->drmdd = (const struct drm_driver_descriptor *)
+ util_dl_get_proc_address(pmod->lib, "driver_descriptor");
+
+ /* sanity check on the name */
+ if (pmod->drmdd && strcmp(pmod->drmdd->name, pmod->name) != 0)
+ pmod->drmdd = NULL;
+
+ if (!pmod->drmdd) {
+ util_dl_close(pmod->lib);
+ pmod->lib = NULL;
+ }
+ }
+
+ return (pmod->drmdd != NULL);
+}
+
+static struct pipe_module *
+get_pipe_module(const char *name)
+{
+ struct pipe_module *pmod = NULL;
+ int i;
+
+ if (!name)
+ return NULL;
+
+ for (i = 0; i < Elements(pipe_modules); i++) {
+ if (!pipe_modules[i].initialized ||
+ strcmp(pipe_modules[i].name, name) == 0) {
+ pmod = &pipe_modules[i];
+ break;
+ }
+ }
+ if (!pmod)
+ return NULL;
+
+ if (!pmod->initialized) {
+ load_pipe_module(pmod, name);
+ pmod->initialized = TRUE;
+ }
+
+ return pmod;
+}
+
+static struct pipe_screen *
+create_drm_screen(const char *name, int fd)
+{
+ struct pipe_module *pmod = get_pipe_module(name);
+
+ return (pmod && pmod->drmdd && pmod->drmdd->create_screen) ?
+ pmod->drmdd->create_screen(fd) : NULL;
+}
+
+int
+gallium_screen_create(struct gbm_gallium_drm_device *gdrm)
+{
+ gdrm->base.driver_name = util_drm_fd_get_screen_name(gdrm->base.base.fd);
+
+ gdrm->screen = create_drm_screen(gdrm->base.driver_name, gdrm->base.base.fd);
+ if (gdrm->screen == NULL) {
+ debug_printf("failed to load driver: %s\n", gdrm->base.driver_name);
+ return -1;
+ };
+
+ return 0;
+}
+
+static int
+gallium_drm_probe(int fd)
+{
+ char *name;
+ int ret = 0;
+
+ name = util_drm_fd_get_screen_name(fd);
+ if (name == NULL) {
+ ret = -1;
+ } else {
+ free(name);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+GBM_EXPORT struct gbm_backend gbm_backend = {
+ .class_name = "drm",
+ .backend_name = "gallium",
+ .probe = gallium_drm_probe,
+ .create_device = gbm_gallium_drm_device_create,
+};
diff --git a/src/gallium/targets/gbm/pci_list.c b/src/gallium/targets/gbm/pci_list.c
new file mode 100644
index 0000000000..6f2a3019f9
--- /dev/null
+++ b/src/gallium/targets/gbm/pci_list.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include "util/u_string.h"
+#include "util/u_memory.h"
+
+#include <libudev.h>
+
+#include "pci_list.h"
+#include "gbm_gallium_drmint.h"
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+
+static INLINE char *
+_strdup(const char *str)
+{
+ return mem_dup(str, strlen(str) + 1);
+}
+
+char *
+util_drm_fd_get_screen_name(int fd)
+{
+ struct udev *udev;
+ struct udev_device *device, *parent;
+ const char *pci_id;
+ char *driver = NULL;
+ int vendor_id, chip_id, i, j;
+
+ udev = udev_new();
+ device = _gbm_udev_device_new_from_fd(udev, fd);
+ if (device == NULL)
+ return NULL;
+
+ parent = udev_device_get_parent(device);
+ if (parent == NULL) {
+ fprintf(stderr, "gbm: could not get parent device");
+ goto out;
+ }
+
+ pci_id = udev_device_get_property_value(parent, "PCI_ID");
+ if (pci_id == NULL ||
+ sscanf(pci_id, "%x:%x", &vendor_id, &chip_id) != 2) {
+ fprintf(stderr, "gbm: malformed or no PCI ID");
+ goto out;
+ }
+
+ for (i = 0; i < Elements(driver_map); i++) {
+ if (vendor_id != driver_map[i].vendor_id)
+ continue;
+ if (driver_map[i].num_chips_ids == -1) {
+ driver = strdup(driver_map[i].driver);
+#if 0
+ fprintf(stderr, "pci id for %d: %04x:%04x, driver %s",
+ fd, vendor_id, chip_id, driver);
+#endif
+ goto out;
+ }
+
+ for (j = 0; j < driver_map[i].num_chips_ids; j++)
+ if (driver_map[i].chip_ids[j] == chip_id) {
+ driver = strdup(driver_map[i].driver);
+#if 0
+ fprintf(stderr,
+ "pci id for %d: %04x:%04x, driver %s",
+ fd, vendor_id, chip_id, driver);
+#endif
+ goto out;
+ }
+ }
+
+out:
+ udev_device_unref(device);
+ udev_unref(udev);
+
+ return driver;
+}