| |
| #include "utils.h" |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include "egl_tracker.h" |
| |
| #include <fcntl.h> |
| |
| #include "egllog.h" |
| #include "state_tracker/drm_api.h" |
| |
| #include "pipe/p_screen.h" |
| #include "pipe/internal/p_winsys_screen.h" |
| |
| /** HACK */ |
| void* driDriverAPI; |
| |
| |
| /* |
| * 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; |
| |
| 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; |
| } |