diff options
author | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2011-05-26 15:11:50 +0200 |
---|---|---|
committer | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2011-05-30 14:37:19 +0200 |
commit | 790a4793c496af39fe00a203ea67ddaef607ad1a (patch) | |
tree | cf38500d4deab64ca87a55ed30a06a968dcd6aab | |
parent | 621d36fe4f6b6effc9bf3bf15eeeaa611b1faccb (diff) |
gbm: Add gallium (drm) backend
-rw-r--r-- | configure.ac | 15 | ||||
-rw-r--r-- | src/gallium/state_trackers/gbm/Makefile | 46 | ||||
-rw-r--r-- | src/gallium/state_trackers/gbm/gbm_g3d_drm.c | 209 | ||||
-rw-r--r-- | src/gallium/state_trackers/gbm/gbm_gallium_drmint.h | 51 | ||||
-rw-r--r-- | src/gallium/targets/gbm/.gitignore | 1 | ||||
-rw-r--r-- | src/gallium/targets/gbm/Makefile | 41 | ||||
l--------- | src/gallium/targets/gbm/extract_pci_list.sh | 1 | ||||
-rw-r--r-- | src/gallium/targets/gbm/gbm.c | 172 | ||||
-rw-r--r-- | src/gallium/targets/gbm/pci_list.c | 74 |
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; +} |