#include "instance.h" #include #include #include #include #include #if ENABLE_XCB # include # include #endif // ENABLE_XCB #define EDID_SIZE (0x80) static int drm_find_psvr_fd(Instance * instance, int fd) { drmModeRes * resources = NULL; drmModeConnector * connector = NULL; drmModeEncoder * encoder = NULL; resources = drmModeGetResources(fd); if (!resources) { //fprintf(stderr, "drmModeGetResources failed\n"); return(0); } if (resources->count_connectors <= 0) { //fprintf(stderr, "no connector\n"); return(0); } int i = 0; for (i = 0; i < resources->count_connectors; i++) { drmModeConnector * connectorToTest = drmModeGetConnector(fd, resources->connectors[i]); if (connectorToTest == NULL) { continue; } if (connectorToTest->connection != DRM_MODE_CONNECTED) { continue; } if (connectorToTest->count_modes <= 0) { continue; } for (int j = 0; j < connectorToTest->count_props; j++) { drmModePropertyPtr prop = drmModeGetProperty(fd, connectorToTest->props[j]); if (prop) { if (prop->flags & DRM_MODE_PROP_RANGE && strcmp(prop->name, "non-desktop") == 0) { uint64_t value = connectorToTest->prop_values[j]; if (value == 1) { connector = connectorToTest; break; } } else if (prop->flags & DRM_MODE_PROP_BLOB && strcmp(prop->name, "EDID") == 0) { uint64_t value = connectorToTest->prop_values[j]; drmModePropertyBlobPtr blob_ptr = drmModeGetPropertyBlob(fd, value); if (blob_ptr) { char edid[EDID_SIZE]; memcpy(&edid, blob_ptr->data, EDID_SIZE); drmModeFreePropertyBlob(blob_ptr); if (strncmp(edid+95, "SIE HMD *08", 12) == 0) // ugly { connector = connectorToTest; break; } } } drmModeFreeProperty(prop); } } if (connector) { break; } drmModeFreeConnector(connectorToTest); } if (!connector) { return 0; } if (i == resources->count_connectors) { //fprintf(stderr, "No currently active connector found.\n"); return(0); } if (resources->count_encoders <= 0) { //fprintf(stderr, "no encoder\n"); return(0); } for (i = 0; i < resources->count_encoders; i++) { encoder = drmModeGetEncoder(fd, resources->encoders[i]); if (encoder == NULL) { continue; } if (encoder->encoder_id == connector->encoder_id) { break; } drmModeFreeEncoder(encoder); } static drmModeModeInfo force_timing; #if 1 // PSVR force_timing.clock = 297700; force_timing.hdisplay = 1920; force_timing.hsync_start = 2008; force_timing.hsync_end = 2052; force_timing.htotal = 2200; force_timing.vdisplay = 1080; force_timing.vsync_start = 1084; force_timing.vsync_end = 1089; force_timing.vtotal = 1125; #else // VIVE force_timing.clock = 297000; force_timing.hdisplay = 2160; force_timing.hsync_start = 2200; force_timing.hsync_end = 2220; force_timing.htotal = 2266; force_timing.vdisplay = 1200; force_timing.vsync_start = 1228; force_timing.vsync_end = 1230; force_timing.vtotal = 1464; #endif // instance->fd = fd; instance->connector = connector; instance->encoder = encoder; instance->mode = &force_timing; return 1; } static const char device_name[] = "/dev/dri/card1"; static int drm_find_psvr_udev(Instance * instance) { int fd = open(device_name, O_RDWR); // FIXME : use udev to available devices if (fd < 0) { fprintf(stderr, "Can't open device\n"); return 0; } return drm_find_psvr_fd(instance, fd); } #ifdef ENABLE_XCB static int drm_find_psvr_xcb(Instance * instance) { xcb_randr_query_version_cookie_t rqv_c = xcb_randr_query_version(instance->connection, XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION); xcb_randr_query_version_reply_t *rqv_r = xcb_randr_query_version_reply(instance->connection, rqv_c, NULL); if (!rqv_r || rqv_r->minor_version < 6) { printf("No new-enough RandR version\n"); return(0); } xcb_screen_iterator_t s_i; int i_s = 0; for (s_i = xcb_setup_roots_iterator(xcb_get_setup(instance->connection)); s_i.rem; xcb_screen_next(&s_i), i_s++) { printf ("index %d screen %d\n", s_i.index, instance->screen); if (i_s == instance->screen) break; } xcb_window_t root = s_i.data->root; printf("root %x\n", root); xcb_randr_get_screen_resources_cookie_t gsr_c = xcb_randr_get_screen_resources(instance->connection, root); xcb_randr_get_screen_resources_reply_t *gsr_r = xcb_randr_get_screen_resources_reply(instance->connection, gsr_c, NULL); if (!gsr_r) { printf("get_screen_resources failed\n"); return(0); } xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r); int o, c; xcb_randr_output_t output = 0; /* Find a connected but idle output */ for (o = 0; output == 0 && o < gsr_r->num_outputs; o++) { xcb_randr_get_output_info_cookie_t goi_c = xcb_randr_get_output_info(instance->connection, ro[o], gsr_r->config_timestamp); xcb_randr_get_output_info_reply_t *goi_r = xcb_randr_get_output_info_reply(instance->connection, goi_c, NULL); /* Find the first connected but unused output */ if (goi_r->connection == XCB_RANDR_CONNECTION_CONNECTED && goi_r->crtc == 0) { output = ro[o]; } free(goi_r); } xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r); xcb_randr_crtc_t crtc = 0; /* Find an idle crtc */ for (c = 0; crtc == 0 && c < gsr_r->num_crtcs; c++) { xcb_randr_get_crtc_info_cookie_t gci_c = xcb_randr_get_crtc_info(instance->connection, rc[c], gsr_r->config_timestamp); xcb_randr_get_crtc_info_reply_t *gci_r = xcb_randr_get_crtc_info_reply(instance->connection, gci_c, NULL); /* Find the first connected but unused crtc */ if (gci_r->mode == 0) crtc = rc[c]; free(gci_r); } free(gsr_r); printf("output %x crtc %x\n", output, crtc); xcb_randr_lease_t lease = xcb_generate_id(instance->connection); xcb_randr_create_lease_cookie_t rcl_c = xcb_randr_create_lease(instance->connection, root, lease, 1, 1, &crtc, &output); xcb_randr_create_lease_reply_t *rcl_r = xcb_randr_create_lease_reply(instance->connection, rcl_c, NULL); if (!rcl_r) { printf("create_lease failed\n"); exit(1); } int *rcl_f = xcb_randr_create_lease_reply_fds(instance->connection, rcl_r); return drm_find_psvr_fd(instance, rcl_f[0]); } #endif // ENABLE_XCB bool InitInstance(Instance * instance) { #ifdef ENABLE_XCB instance->connection = xcb_connect(NULL, &instance->screen); if (drm_find_psvr_xcb(instance)) { printf("device found using XCB\n"); } else #endif // ENABLE_XCB if (drm_find_psvr_udev(instance)) { printf("device found using udev\n"); } else { fprintf(stderr, "couldn't find devicee\n"); return false; } struct gbm_device * device = gbm_create_device(instance->fd); if (device == NULL) { fprintf(stderr, "couldn't create gbm device\n"); return false; } struct gbm_surface * surface = gbm_surface_create(device, instance->mode->hdisplay, instance->mode->vdisplay, GBM_BO_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); if (surface == NULL) { fprintf(stderr, "couldn't create gbm surface\n"); gbm_device_destroy(device); return false; } instance->device = device; instance->surface = surface; return true; } bool ReleaseInstance(Instance * instance) { (void)instance; return false; // TODO } void SwapBuffers(Instance * instance) { struct gbm_bo * newbo = gbm_surface_lock_front_buffer(instance->surface); uint32_t handle = gbm_bo_get_handle(newbo).u32; uint32_t stride = gbm_bo_get_stride(newbo); { uint32_t newfb = 0; drmModeAddFB(instance->fd, instance->mode->hdisplay, instance->mode->vdisplay, 24, 32, stride, handle, &newfb); int rc = drmModeSetCrtc(instance->fd, instance->encoder->crtc_id, newfb, 0, 0, &instance->connector->connector_id, 1, instance->mode); if (rc < 0) { fprintf(stderr, "drmModeSetCrtc() failed\n"); return; } if (instance->fbid) { drmModeRmFB(instance->fd, instance->fbid); } instance->fbid = newfb; } if (instance->bo) { gbm_surface_release_buffer(instance->surface, instance->bo); } instance->bo = newbo; }