Update API + example
This commit is contained in:
352
src/instance.c
352
src/instance.c
@@ -2,23 +2,331 @@
|
||||
|
||||
#include "lvrc_internal.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if ENABLE_XCB
|
||||
# include <xcb/xcb.h>
|
||||
# include <xcb/randr.h>
|
||||
#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
|
||||
# include <xcb/xcb.h>
|
||||
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
|
||||
|
||||
|
||||
struct lvrcInstance * lvrcCreateInstance(ohmd_device * hmd)
|
||||
{
|
||||
Instance * instance = calloc(1, sizeof(Instance));
|
||||
|
||||
instance->device = hmd;
|
||||
instance->hmd = hmd;
|
||||
|
||||
#ifdef ENABLE_XCB
|
||||
instance->connection = xcb_connect(NULL, &instance->screen);
|
||||
#endif // ENABLE_XCB
|
||||
|
||||
instance->swapChain = NULL;
|
||||
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");
|
||||
free(instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
instance->device = gbm_create_device(instance->fd);
|
||||
|
||||
if (instance->device == NULL)
|
||||
{
|
||||
fprintf(stderr, "couldn't create gbm device\n");
|
||||
free(instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
instance->surface = gbm_surface_create(instance->device, instance->mode->hdisplay, instance->mode->vdisplay, GBM_BO_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
|
||||
|
||||
if (instance->surface == NULL)
|
||||
{
|
||||
fprintf(stderr, "couldn't create gbm surface\n");
|
||||
free(instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (struct lvrcInstance *)instance;
|
||||
}
|
||||
@@ -27,3 +335,37 @@ void lvrcDestroyInstance(struct lvrcInstance * instance)
|
||||
{
|
||||
free(instance);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user