static void gfx_ctx_drm_egl_destroy_resources(gfx_ctx_drm_egl_data_t *drm) { if (!drm) return; /* Make sure we acknowledge all page-flips. */ if (waiting_for_flip) wait_flip(true); if (drm->g_egl_dpy) { if (drm->g_egl_ctx) { eglMakeCurrent(drm->g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(drm->g_egl_dpy, drm->g_egl_ctx); } if (drm->g_egl_hw_ctx) eglDestroyContext(drm->g_egl_dpy, drm->g_egl_hw_ctx); if (drm->g_egl_surf) eglDestroySurface(drm->g_egl_dpy, drm->g_egl_surf); eglTerminate(drm->g_egl_dpy); } /* Be as careful as possible in deinit. * If we screw up, the KMS tty will not restore. */ drm->g_egl_ctx = NULL; drm->g_egl_hw_ctx = NULL; drm->g_egl_surf = NULL; drm->g_egl_dpy = NULL; drm->g_config = 0; /* Restore original CRTC. */ if (drm->g_orig_crtc) { drmModeSetCrtc(drm->g_drm_fd, drm->g_orig_crtc->crtc_id, drm->g_orig_crtc->buffer_id, drm->g_orig_crtc->x, drm->g_orig_crtc->y, &drm->g_connector_id, 1, &drm->g_orig_crtc->mode); } free_drm_resources(drm); drm->g_drm_mode = NULL; g_quit = 0; drm->g_crtc_id = 0; drm->g_connector_id = 0; drm->g_fb_width = 0; drm->g_fb_height = 0; drm->g_bo = NULL; drm->g_next_bo = NULL; }
static void gfx_ctx_drm_destroy_resources(gfx_ctx_drm_data_t *drm) { if (!drm) return; /* Make sure we acknowledge all page-flips. */ gfx_ctx_drm_wait_flip(true); switch (drm_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: case GFX_CTX_OPENVG_API: #ifdef HAVE_EGL egl_destroy(&drm->egl); #endif break; case GFX_CTX_NONE: default: break; } free_drm_resources(drm); g_drm_mode = NULL; g_crtc_id = 0; g_connector_id = 0; drm->fb_width = 0; drm->fb_height = 0; g_bo = NULL; g_next_bo = NULL; }
static void gfx_ctx_drm_egl_destroy(void *data) { (void)data; // Make sure we acknowledge all page-flips. if (waiting_for_flip) wait_flip(true); if (g_egl_dpy) { if (g_egl_ctx) { eglMakeCurrent(g_egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(g_egl_dpy, g_egl_ctx); } if (g_egl_hw_ctx) eglDestroyContext(g_egl_dpy, g_egl_hw_ctx); if (g_egl_surf) eglDestroySurface(g_egl_dpy, g_egl_surf); eglTerminate(g_egl_dpy); } // Be as careful as possible in deinit. // If we screw up, the KMS tty will not restore. g_egl_ctx = NULL; g_egl_hw_ctx = NULL; g_egl_surf = NULL; g_egl_dpy = NULL; g_config = 0; // Restore original CRTC. if (g_orig_crtc) { drmModeSetCrtc(g_drm_fd, g_orig_crtc->crtc_id, g_orig_crtc->buffer_id, g_orig_crtc->x, g_orig_crtc->y, &g_connector_id, 1, &g_orig_crtc->mode); } free_drm_resources(); g_drm_mode = NULL; g_quit = 0; g_crtc_id = 0; g_connector_id = 0; g_fb_width = 0; g_fb_height = 0; g_bo = NULL; g_next_bo = NULL; g_inited = false; }
static bool gfx_ctx_drm_egl_init(void *data) { const char *gpu; int i; unsigned monitor_index; unsigned gpu_index = 0; unsigned monitor = max(g_settings.video.monitor_index, 1); struct string_list *gpu_descriptors = NULL; gfx_ctx_drm_egl_data_t *drm = (gfx_ctx_drm_egl_data_t*)calloc(1, sizeof(gfx_ctx_drm_egl_data_t)); if (!drm) return NULL; drm->g_drm_fd = -1; gpu_descriptors = (struct string_list*)dir_list_new("/dev/dri", NULL, false); nextgpu: free_drm_resources(drm); if (!gpu_descriptors || gpu_index == gpu_descriptors->size) { RARCH_ERR("[KMS/EGL]: Couldn't find a suitable DRM device.\n"); goto error; } gpu = gpu_descriptors->elems[gpu_index++].data; drm->g_drm_fd = open(gpu, O_RDWR); if (drm->g_drm_fd < 0) { RARCH_WARN("[KMS/EGL]: Couldn't open DRM device.\n"); goto nextgpu; } drm->g_resources = drmModeGetResources(drm->g_drm_fd); if (!drm->g_resources) { RARCH_WARN("[KMS/EGL]: Couldn't get device resources.\n"); goto nextgpu; } /* Enumerate all connectors. */ monitor_index = 0; RARCH_LOG("[KMS/EGL]: Found %d connectors.\n", drm->g_resources->count_connectors); for (i = 0; i < drm->g_resources->count_connectors; i++) { drmModeConnectorPtr conn = drmModeGetConnector( drm->g_drm_fd, drm->g_resources->connectors[i]); if (conn) { bool connected = conn->connection == DRM_MODE_CONNECTED; RARCH_LOG("[KMS/EGL]: Connector %d connected: %s\n", i, connected ? "yes" : "no"); RARCH_LOG("[KMS/EGL]: Connector %d has %d modes.\n", i, conn->count_modes); if (connected && conn->count_modes > 0) { monitor_index++; RARCH_LOG("[KMS/EGL]: Connector %d assigned to monitor index: #%u.\n", i, monitor_index); } drmModeFreeConnector(conn); } } monitor_index = 0; for (i = 0; i < drm->g_resources->count_connectors; i++) { drm->g_connector = drmModeGetConnector(drm->g_drm_fd, drm->g_resources->connectors[i]); if (!drm->g_connector) continue; if (drm->g_connector->connection == DRM_MODE_CONNECTED && drm->g_connector->count_modes > 0) { monitor_index++; if (monitor_index == monitor) break; } drmModeFreeConnector(drm->g_connector); drm->g_connector = NULL; } if (!drm->g_connector) { RARCH_WARN("[KMS/EGL]: Couldn't get device connector.\n"); goto nextgpu; } for (i = 0; i < drm->g_resources->count_encoders; i++) { drm->g_encoder = drmModeGetEncoder(drm->g_drm_fd, drm->g_resources->encoders[i]); if (!drm->g_encoder) continue; if (drm->g_encoder->encoder_id == drm->g_connector->encoder_id) break; drmModeFreeEncoder(drm->g_encoder); drm->g_encoder = NULL; } if (!drm->g_encoder) { RARCH_WARN("[KMS/EGL]: Couldn't find DRM encoder.\n"); goto nextgpu; } for (i = 0; i < drm->g_connector->count_modes; i++) { RARCH_LOG("[KMS/EGL]: Mode %d: (%s) %d x %d, %u Hz\n", i, drm->g_connector->modes[i].name, drm->g_connector->modes[i].hdisplay, drm->g_connector->modes[i].vdisplay, drm->g_connector->modes[i].vrefresh); } drm->g_crtc_id = drm->g_encoder->crtc_id; drm->g_orig_crtc = drmModeGetCrtc(drm->g_drm_fd, drm->g_crtc_id); if (!drm->g_orig_crtc) RARCH_WARN("[KMS/EGL]: Cannot find original CRTC.\n"); drm->g_connector_id = drm->g_connector->connector_id; /* First mode is assumed to be the "optimal" * one for get_video_size() purposes. */ drm->g_fb_width = drm->g_connector->modes[0].hdisplay; drm->g_fb_height = drm->g_connector->modes[0].vdisplay; drm->g_gbm_dev = gbm_create_device(drm->g_drm_fd); if (!drm->g_gbm_dev) { RARCH_WARN("[KMS/EGL]: Couldn't create GBM device.\n"); goto nextgpu; } dir_list_free(gpu_descriptors); driver.video_context_data = drm; return true; error: dir_list_free(gpu_descriptors); gfx_ctx_drm_egl_destroy_resources(drm); if (drm) free(drm); return false; }
static void *gfx_ctx_drm_init(void *video_driver) { int fd, i; unsigned monitor_index; unsigned gpu_index = 0; const char *gpu = NULL; struct string_list *gpu_descriptors = NULL; gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*) calloc(1, sizeof(gfx_ctx_drm_data_t)); if (!drm) return NULL; gpu_descriptors = dir_list_new("/dev/dri", NULL, false, true, false, false); nextgpu: free_drm_resources(drm); if (!gpu_descriptors || gpu_index == gpu_descriptors->size) { RARCH_ERR("[KMS]: Couldn't find a suitable DRM device.\n"); goto error; } gpu = gpu_descriptors->elems[gpu_index++].data; drm->drm = filestream_open(gpu, RFILE_MODE_READ_WRITE, -1); if (!drm->drm) { RARCH_WARN("[KMS]: Couldn't open DRM device.\n"); goto nextgpu; } fd = filestream_get_fd(drm->drm); if (!drm_get_resources(fd)) goto nextgpu; if (!drm_get_connector(fd)) goto nextgpu; if (!drm_get_encoder(fd)) goto nextgpu; drm_setup(fd); /* First mode is assumed to be the "optimal" * one for get_video_size() purposes. */ drm->fb_width = g_drm_connector->modes[0].hdisplay; drm->fb_height = g_drm_connector->modes[0].vdisplay; g_gbm_dev = gbm_create_device(fd); if (!g_gbm_dev) { RARCH_WARN("[KMS]: Couldn't create GBM device.\n"); goto nextgpu; } dir_list_free(gpu_descriptors); /* Setup the flip handler. */ g_drm_fds.fd = fd; g_drm_fds.events = POLLIN; g_drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; g_drm_evctx.page_flip_handler = drm_flip_handler; g_drm_fd = fd; return drm; error: dir_list_free(gpu_descriptors); gfx_ctx_drm_destroy_resources(drm); if (drm) free(drm); return NULL; }