#include "utils.h" #include #include #include #include "egl_tracker.h" #include #include "egllog.h" #include "state_tracker/drm_api.h" #include "pipe/p_screen.h" #include "pipe/internal/p_winsys_screen.h" /** HACK */ void* driDriverAPI; extern const struct dri_extension card_extensions[]; /* * Exported functions */ static void drm_unload(_EGLDriver *drv) { free(drv); } /** * The bootstrap function. Return a new drm_driver object and * plug in API functions. */ _EGLDriver * _eglMain(const char *args) { _EGLDriver *drv; drv = (_EGLDriver *) calloc(1, sizeof(_EGLDriver)); if (!drv) { return NULL; } /* First fill in the dispatch table with defaults */ _eglInitDriverFallbacks(drv); /* then plug in our Drm-specific functions */ drv->API.Initialize = drm_initialize; drv->API.Terminate = drm_terminate; drv->API.CreateContext = drm_create_context; drv->API.MakeCurrent = drm_make_current; drv->API.CreateWindowSurface = drm_create_window_surface; drv->API.CreatePixmapSurface = drm_create_pixmap_surface; drv->API.CreatePbufferSurface = drm_create_pbuffer_surface; drv->API.DestroySurface = drm_destroy_surface; drv->API.DestroyContext = drm_destroy_context; drv->API.CreateScreenSurfaceMESA = drm_create_screen_surface_mesa; drv->API.ShowScreenSurfaceMESA = drm_show_screen_surface_mesa; drv->API.SwapBuffers = drm_swap_buffers; drv->Name = "DRM/Gallium/Win"; drv->Unload = drm_unload; return drv; } static void drm_get_device_id(struct drm_device *device) { char path[512]; FILE *file; char *ret; /* TODO get the real minor */ int minor = 0; device->deviceID = 0; snprintf(path, sizeof(path), "/sys/class/drm/card%d/device/device", minor); file = fopen(path, "r"); if (!file) { _eglLog(_EGL_WARNING, "Could not retrive device ID\n"); return; } ret = fgets(path, sizeof( path ), file); if (!ret) return; sscanf(path, "%x", &device->deviceID); fclose(file); } static void drm_update_res(struct drm_device *dev) { drmModeFreeResources(dev->res); dev->res = drmModeGetResources(dev->drmFD); } static void drm_add_modes_from_connector(_EGLScreen *screen, drmModeConnectorPtr connector) { drmModeModeInfoPtr m = NULL; int i; for (i = 0; i < connector->count_modes; i++) { m = &connector->modes[i]; _eglAddNewMode(screen, m->hdisplay, m->vdisplay, m->vrefresh, m->name); } } static void drm_find_dpms(struct drm_device *dev, struct drm_screen *screen) { drmModeConnectorPtr c = screen->connector; drmModePropertyPtr p; int i; for (i = 0; i < c->count_props; i++) { p = drmModeGetProperty(dev->drmFD, c->props[i]); if (!strcmp(p->name, "DPMS")) break; drmModeFreeProperty(p); p = NULL; } screen->dpms = p; } static int drm_open_minor(int minor) { char buf[64]; sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor); return open(buf, O_RDWR, 0); } EGLBoolean drm_initialize(_EGLDriver *drv, _EGLDisplay *disp, EGLint *major, EGLint *minor) { struct drm_device *dev; struct drm_screen *screen = NULL; drmModeConnectorPtr connector = NULL; drmModeResPtr res = NULL; unsigned count_connectors = 0; int num_screens = 0; EGLint i; int fd; dev = (struct drm_device *) calloc(1, sizeof(struct drm_device)); if (!dev) return EGL_FALSE; dev->api = drm_api_create(); /* try the first node */ fd = drm_open_minor(0); if (fd < 0) goto err_fd; dev->drmFD = fd; drm_get_device_id(dev); dev->screen = dev->api->create_screen(dev->api, dev->drmFD, NULL); if (!dev->screen) goto err_screen; dev->winsys = dev->screen->winsys; /* TODO HACK */ driInitExtensions(NULL, card_extensions, GL_FALSE); drm_update_res(dev); res = dev->res; if (res) count_connectors = res->count_connectors; else _eglLog(_EGL_WARNING, "Could not retrive kms information\n"); for(i = 0; i < count_connectors && i < MAX_SCREENS; i++) { connector = drmModeGetConnector(fd, res->connectors[i]); if (!connector) continue; if (connector->connection != DRM_MODE_CONNECTED) { drmModeFreeConnector(connector); continue; } screen = malloc(sizeof(struct drm_screen)); memset(screen, 0, sizeof(*screen)); screen->connector = connector; screen->connectorID = connector->connector_id; _eglInitScreen(&screen->base); _eglAddScreen(disp, &screen->base); drm_add_modes_from_connector(&screen->base, connector); drm_find_dpms(dev, screen); dev->screens[num_screens++] = screen; } dev->count_screens = num_screens; disp->DriverData = dev; /* for now we only have one config */ _EGLConfig *config = calloc(1, sizeof(*config)); memset(config, 1, sizeof(*config)); _eglInitConfig(config, 1); _eglSetConfigAttrib(config, EGL_RED_SIZE, 8); _eglSetConfigAttrib(config, EGL_GREEN_SIZE, 8); _eglSetConfigAttrib(config, EGL_BLUE_SIZE, 8); _eglSetConfigAttrib(config, EGL_ALPHA_SIZE, 8); _eglSetConfigAttrib(config, EGL_BUFFER_SIZE, 32); _eglSetConfigAttrib(config, EGL_DEPTH_SIZE, 24); _eglSetConfigAttrib(config, EGL_STENCIL_SIZE, 8); _eglSetConfigAttrib(config, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT); _eglAddConfig(disp, config); disp->ClientAPIsMask = EGL_OPENGL_BIT /*| EGL_OPENGL_ES_BIT*/; /* enable supported extensions */ disp->Extensions.MESA_screen_surface = EGL_TRUE; disp->Extensions.MESA_copy_context = EGL_TRUE; *major = 1; *minor = 4; return EGL_TRUE; err_screen: drmClose(fd); err_fd: free(dev); return EGL_FALSE; } EGLBoolean drm_terminate(_EGLDriver *drv, _EGLDisplay *dpy) { struct drm_device *dev = lookup_drm_device(dpy); struct drm_screen *screen; int i = 0; _eglReleaseDisplayResources(drv, dpy); _eglCleanupDisplay(dpy); drmFreeVersion(dev->version); for (i = 0; i < dev->count_screens; i++) { screen = dev->screens[i]; if (screen->shown) drm_takedown_shown_screen(dpy, screen); drmModeFreeProperty(screen->dpms); drmModeFreeConnector(screen->connector); _eglDestroyScreen(&screen->base); dev->screens[i] = NULL; } dev->screen->destroy(dev->screen); dev->winsys = NULL; drmClose(dev->drmFD); dev->api->destroy(dev->api); free(dev); dpy->DriverData = NULL; return EGL_TRUE; }