714 lines
21 KiB
C
714 lines
21 KiB
C
#include "e.h"
|
|
#include "e_mod_main.h"
|
|
|
|
/* local function prototypes */
|
|
static void _cb_tty(E_Compositor *comp, int event);
|
|
static int _cb_drm_input(int fd, unsigned int mask __UNUSED__, void *data __UNUSED__);
|
|
static int _cb_drm_udev_event(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data);
|
|
static void _cb_drm_page_flip(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec, unsigned int usec, void *data);
|
|
static void _cb_drm_vblank(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec __UNUSED__, unsigned int usec __UNUSED__, void *data);
|
|
static Eina_Bool _egl_init(E_Drm_Compositor *dcomp, struct udev_device *dev);
|
|
static void _sprites_init(E_Drm_Compositor *dcomp);
|
|
static void _sprites_shutdown(E_Drm_Compositor *dcomp);
|
|
static Eina_Bool _outputs_init(E_Drm_Compositor *dcomp, unsigned int conn, struct udev_device *drm_device);
|
|
static Eina_Bool _output_create(E_Drm_Compositor *dcomp, drmModeRes *res, drmModeConnector *conn, int x, int y, struct udev_device *drm_device);
|
|
static void _outputs_update(E_Drm_Compositor *dcomp, struct udev_device *drm_device);
|
|
static Eina_Bool _udev_event_is_hotplug(E_Drm_Compositor *dcomp, struct udev_device *dev);
|
|
|
|
/* local variables */
|
|
static drmModeModeInfo builtin_mode =
|
|
{
|
|
63500, /* clock */
|
|
1024, 1072, 1176, 1328, 0,
|
|
768, 771, 775, 798, 0,
|
|
59920,
|
|
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
|
|
0,
|
|
"1024x768"
|
|
};
|
|
|
|
/* external variables */
|
|
E_Drm_Compositor *_drm_comp = NULL;
|
|
|
|
EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Drm" };
|
|
|
|
EAPI void *
|
|
e_modapi_init(E_Module *m)
|
|
{
|
|
struct wl_display *disp;
|
|
struct udev_enumerate *ue;
|
|
struct udev_list_entry *entry;
|
|
struct udev_device *drm_dev = NULL;
|
|
struct wl_event_loop *loop;
|
|
const char *seat = NULL;
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
/* try to get the wayland display */
|
|
if (!(disp = (struct wl_display *)m->data)) return NULL;
|
|
|
|
/* allocate space for the drm compositor */
|
|
if (!(_drm_comp = malloc(sizeof(E_Drm_Compositor)))) return NULL;
|
|
|
|
memset(_drm_comp, 0, sizeof(E_Drm_Compositor));
|
|
|
|
if (!(_drm_comp->udev = udev_new()))
|
|
{
|
|
free(_drm_comp);
|
|
return NULL;
|
|
}
|
|
|
|
_drm_comp->base.display = disp;
|
|
if (!(_drm_comp->tty = e_tty_create(&_drm_comp->base, _cb_tty, 0)))
|
|
{
|
|
free(_drm_comp);
|
|
return NULL;
|
|
}
|
|
|
|
ue = udev_enumerate_new(_drm_comp->udev);
|
|
udev_enumerate_add_match_subsystem(ue, "drm");
|
|
udev_enumerate_add_match_sysname(ue, "card[0-9]*");
|
|
|
|
udev_enumerate_scan_devices(ue);
|
|
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(ue))
|
|
{
|
|
struct udev_device *dev;
|
|
const char *path = NULL;
|
|
|
|
path = udev_list_entry_get_name(entry);
|
|
dev = udev_device_new_from_syspath(_drm_comp->udev, path);
|
|
if (!(seat = udev_device_get_property_value(dev, "ID_SEAT")))
|
|
seat = "seat0";
|
|
if (!strcmp(seat, "seat0"))
|
|
{
|
|
drm_dev = dev;
|
|
break;
|
|
}
|
|
udev_device_unref(dev);
|
|
}
|
|
|
|
if (!drm_dev)
|
|
{
|
|
free(_drm_comp);
|
|
return NULL;
|
|
}
|
|
|
|
/* init egl */
|
|
if (!_egl_init(_drm_comp, drm_dev))
|
|
{
|
|
free(_drm_comp);
|
|
return NULL;
|
|
}
|
|
|
|
/* _drm_comp->base.destroy = _cb_destroy; */
|
|
_drm_comp->base.focus = EINA_TRUE;
|
|
|
|
_drm_comp->prev_state = E_COMPOSITOR_STATE_ACTIVE;
|
|
|
|
glGenFramebuffers(1, &_drm_comp->base.fbo);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, _drm_comp->base.fbo);
|
|
|
|
if (!e_compositor_init(&_drm_comp->base, disp))
|
|
{
|
|
free(_drm_comp);
|
|
return NULL;
|
|
}
|
|
|
|
wl_list_init(&_drm_comp->sprites);
|
|
_sprites_init(_drm_comp);
|
|
|
|
if (!_outputs_init(_drm_comp, 0, drm_dev))
|
|
{
|
|
free(_drm_comp);
|
|
return NULL;
|
|
}
|
|
|
|
udev_device_unref(drm_dev);
|
|
udev_enumerate_unref(ue);
|
|
|
|
e_evdev_input_create(&_drm_comp->base, _drm_comp->udev, seat);
|
|
|
|
loop = wl_display_get_event_loop(_drm_comp->base.display);
|
|
_drm_comp->drm_source =
|
|
wl_event_loop_add_fd(loop, _drm_comp->drm.fd, WL_EVENT_READABLE,
|
|
_cb_drm_input, _drm_comp);
|
|
|
|
_drm_comp->udev_monitor =
|
|
udev_monitor_new_from_netlink(_drm_comp->udev, "udev");
|
|
if (!_drm_comp->udev_monitor)
|
|
{
|
|
free(_drm_comp);
|
|
return NULL;
|
|
}
|
|
udev_monitor_filter_add_match_subsystem_devtype(_drm_comp->udev_monitor,
|
|
"drm", NULL);
|
|
|
|
_drm_comp->udev_drm_source =
|
|
wl_event_loop_add_fd(loop, udev_monitor_get_fd(_drm_comp->udev_monitor),
|
|
WL_EVENT_READABLE, _cb_drm_udev_event, _drm_comp);
|
|
if (udev_monitor_enable_receiving(_drm_comp->udev_monitor) < 0)
|
|
{
|
|
free(_drm_comp);
|
|
return NULL;
|
|
}
|
|
|
|
return &_drm_comp->base;
|
|
}
|
|
|
|
EAPI int
|
|
e_modapi_shutdown(E_Module *m __UNUSED__)
|
|
{
|
|
E_Input_Device *input, *next;
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
e_compositor_shutdown(&_drm_comp->base);
|
|
gbm_device_destroy(_drm_comp->gbm);
|
|
_sprites_shutdown(_drm_comp);
|
|
drmDropMaster(_drm_comp->drm.fd);
|
|
e_tty_destroy(_drm_comp->tty);
|
|
|
|
wl_list_for_each_safe(input, next, &_drm_comp->base.inputs, link)
|
|
e_evdev_input_destroy(input);
|
|
|
|
free(_drm_comp);
|
|
_drm_comp = NULL;
|
|
|
|
return 1;
|
|
}
|
|
|
|
EAPI int
|
|
e_modapi_save(E_Module *m __UNUSED__)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/* local function prototypes */
|
|
static void
|
|
_cb_tty(E_Compositor *comp, int event)
|
|
{
|
|
E_Output *output;
|
|
E_Drm_Output *doutput;
|
|
E_Sprite *sprite;
|
|
E_Input_Device *input;
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
switch (event)
|
|
{
|
|
case 0: // TTY_ENTER_VT
|
|
comp->focus = EINA_TRUE;
|
|
if (drmSetMaster(_drm_comp->drm.fd))
|
|
{
|
|
printf("Failed to set master: %m\n");
|
|
wl_display_terminate(comp->display);
|
|
}
|
|
comp->state = _drm_comp->prev_state;
|
|
e_drm_output_set_modes(_drm_comp);
|
|
e_compositor_damage_all(comp);
|
|
wl_list_for_each(input, &comp->inputs, link)
|
|
e_evdev_add_devices(_drm_comp->udev, input);
|
|
break;
|
|
case 1: // TTY_LEAVE_VT
|
|
comp->focus = EINA_FALSE;
|
|
_drm_comp->prev_state = comp->state;
|
|
comp->state = E_COMPOSITOR_STATE_SLEEPING;
|
|
wl_list_for_each(output, &comp->outputs, link)
|
|
{
|
|
output->repaint_needed = EINA_FALSE;
|
|
e_drm_output_set_cursor(output, NULL);
|
|
}
|
|
doutput =
|
|
container_of(comp->outputs.next, E_Drm_Output, base.link);
|
|
|
|
wl_list_for_each(sprite, &_drm_comp->sprites, link)
|
|
drmModeSetPlane(_drm_comp->drm.fd, sprite->plane_id,
|
|
doutput->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
|
|
wl_list_for_each(input, &comp->inputs, link)
|
|
e_evdev_remove_devices(input);
|
|
|
|
if (drmDropMaster(_drm_comp->drm.fd < 0))
|
|
printf("Failed to drop master: %m\n");
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int
|
|
_cb_drm_input(int fd, unsigned int mask __UNUSED__, void *data __UNUSED__)
|
|
{
|
|
drmEventContext ectxt;
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
memset(&ectxt, 0, sizeof(ectxt));
|
|
|
|
ectxt.version = DRM_EVENT_CONTEXT_VERSION;
|
|
ectxt.page_flip_handler = _cb_drm_page_flip;
|
|
ectxt.vblank_handler = _cb_drm_vblank;
|
|
drmHandleEvent(fd, &ectxt);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_cb_drm_udev_event(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data)
|
|
{
|
|
E_Drm_Compositor *dcomp;
|
|
struct udev_device *event;
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if (!(dcomp = data)) return 1;
|
|
event = udev_monitor_receive_device(dcomp->udev_monitor);
|
|
if (_udev_event_is_hotplug(dcomp, event))
|
|
_outputs_update(dcomp, event);
|
|
udev_device_unref(event);
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
_cb_drm_page_flip(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec, unsigned int usec, void *data)
|
|
{
|
|
E_Drm_Output *doutput;
|
|
E_Drm_Compositor *dcomp;
|
|
unsigned int msecs;
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if (!(doutput = data)) return;
|
|
dcomp = (E_Drm_Compositor *)doutput->base.compositor;
|
|
|
|
if (doutput->scanout_buffer)
|
|
{
|
|
e_buffer_post_release(doutput->scanout_buffer);
|
|
wl_list_remove(&doutput->scanout_buffer_destroy_listener.link);
|
|
doutput->scanout_buffer = NULL;
|
|
drmModeRmFB(dcomp->drm.fd, doutput->fs_surf_fb_id);
|
|
doutput->fs_surf_fb_id = 0;
|
|
}
|
|
|
|
if (doutput->pending_scanout_buffer)
|
|
{
|
|
doutput->scanout_buffer = doutput->pending_scanout_buffer;
|
|
wl_list_remove(&doutput->pending_scanout_buffer_destroy_listener.link);
|
|
wl_signal_add(&doutput->scanout_buffer->resource.destroy_signal,
|
|
&doutput->scanout_buffer_destroy_listener);
|
|
doutput->pending_scanout_buffer = NULL;
|
|
doutput->fs_surf_fb_id = doutput->pending_fs_surf_fb_id;
|
|
doutput->pending_fs_surf_fb_id = 0;
|
|
}
|
|
|
|
msecs = sec * 1000 + usec / 1000;
|
|
e_output_finish_frame(&doutput->base, msecs);
|
|
}
|
|
|
|
static void
|
|
_cb_drm_vblank(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec __UNUSED__, unsigned int usec __UNUSED__, void *data)
|
|
{
|
|
E_Sprite *es;
|
|
E_Drm_Compositor *dcomp;
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if (!(es = data)) return;
|
|
dcomp = es->compositor;
|
|
|
|
if (es->surface)
|
|
{
|
|
e_buffer_post_release(es->surface->buffer);
|
|
wl_list_remove(&es->destroy_listener.link);
|
|
es->surface = NULL;
|
|
drmModeRmFB(dcomp->drm.fd, es->fb_id);
|
|
es->fb_id = 0;
|
|
}
|
|
|
|
if (es->pending_surface)
|
|
{
|
|
wl_list_remove(&es->pending_destroy_listener.link);
|
|
wl_signal_add(&es->pending_surface->buffer->resource.destroy_signal,
|
|
&es->destroy_listener);
|
|
es->surface = es->pending_surface;
|
|
es->pending_surface = NULL;
|
|
es->fb_id = es->pending_fb_id;
|
|
es->pending_fb_id = 0;
|
|
}
|
|
}
|
|
|
|
static Eina_Bool
|
|
_egl_init(E_Drm_Compositor *dcomp, struct udev_device *dev)
|
|
{
|
|
EGLint maj, min;
|
|
const char *ext, *fname, *snum;
|
|
int fd = 0;
|
|
static const EGLint ctxt_att[] =
|
|
{
|
|
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
|
|
};
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if ((snum = udev_device_get_sysnum(dev)))
|
|
dcomp->drm.id = atoi(snum);
|
|
if ((!snum) || (dcomp->drm.id < 0))
|
|
return EINA_FALSE;
|
|
|
|
fname = udev_device_get_devnode(dev);
|
|
if (!(fd = open(fname, (O_RDWR | O_CLOEXEC))))
|
|
return EINA_FALSE;
|
|
|
|
dcomp->drm.fd = fd;
|
|
dcomp->gbm = gbm_create_device(dcomp->drm.fd);
|
|
|
|
// dcomp->base.egl_display = eglGetDisplay(dcomp->base.display);
|
|
dcomp->base.egl_display = eglGetDisplay(dcomp->gbm);
|
|
if (!dcomp->base.egl_display)
|
|
return EINA_FALSE;
|
|
|
|
if (!eglInitialize(dcomp->base.egl_display, &maj, &min))
|
|
return EINA_FALSE;
|
|
|
|
ext = eglQueryString(dcomp->base.egl_display, EGL_EXTENSIONS);
|
|
if (!strstr(ext, "EGL_KHR_surfaceless_gles2"))
|
|
return EINA_FALSE;
|
|
|
|
if (!eglBindAPI(EGL_OPENGL_ES_API)) return EINA_FALSE;
|
|
|
|
dcomp->base.egl_context =
|
|
eglCreateContext(dcomp->base.egl_display, NULL, EGL_NO_CONTEXT, ctxt_att);
|
|
if (!dcomp->base.egl_context) return EINA_FALSE;
|
|
|
|
if (!eglMakeCurrent(dcomp->base.egl_display, EGL_NO_SURFACE,
|
|
EGL_NO_SURFACE, dcomp->base.egl_context))
|
|
return EINA_FALSE;
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static void
|
|
_sprites_init(E_Drm_Compositor *dcomp)
|
|
{
|
|
E_Sprite *es;
|
|
drmModePlaneRes *res;
|
|
drmModePlane *plane;
|
|
unsigned int i = 0;
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if (!(res = drmModeGetPlaneResources(dcomp->drm.fd)))
|
|
return;
|
|
|
|
for (i = 0; i < res->count_planes; i++)
|
|
{
|
|
if (!(plane = drmModeGetPlane(dcomp->drm.fd, res->planes[i])))
|
|
continue;
|
|
if (!(es = e_sprite_create(dcomp, plane)))
|
|
{
|
|
free(plane);
|
|
continue;
|
|
}
|
|
drmModeFreePlane(plane);
|
|
wl_list_insert(&dcomp->sprites, &es->link);
|
|
}
|
|
free(res->planes);
|
|
free(res);
|
|
}
|
|
|
|
static void
|
|
_sprites_shutdown(E_Drm_Compositor *dcomp)
|
|
{
|
|
E_Drm_Output *doutput;
|
|
E_Sprite *es, *next;
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
doutput = container_of(dcomp->base.outputs.next, E_Drm_Output, base.link);
|
|
|
|
wl_list_for_each_safe(es, next, &dcomp->sprites, link)
|
|
{
|
|
drmModeSetPlane(dcomp->drm.fd, es->plane_id, doutput->crtc_id,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
drmModeRmFB(dcomp->drm.fd, es->fb_id);
|
|
free(es);
|
|
}
|
|
}
|
|
|
|
static Eina_Bool
|
|
_outputs_init(E_Drm_Compositor *dcomp, unsigned int conn, struct udev_device *drm_device)
|
|
{
|
|
drmModeConnector *connector;
|
|
drmModeRes *res;
|
|
int i = 0, x = 0, y = 0;
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if (!(res = drmModeGetResources(dcomp->drm.fd)))
|
|
return EINA_FALSE;
|
|
|
|
if (!(dcomp->crtcs = calloc(res->count_crtcs, sizeof(unsigned int))))
|
|
{
|
|
drmModeFreeResources(res);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
dcomp->num_crtcs = res->count_crtcs;
|
|
memcpy(dcomp->crtcs, res->crtcs, sizeof(unsigned int) * dcomp->num_crtcs);
|
|
|
|
for (i = 0; i < res->count_connectors; i++)
|
|
{
|
|
if (!(connector =
|
|
drmModeGetConnector(dcomp->drm.fd, res->connectors[i])))
|
|
continue;
|
|
if ((connector->connection == DRM_MODE_CONNECTED) &&
|
|
((conn == 0) || (connector->connector_id == conn)))
|
|
{
|
|
if (!_output_create(dcomp, res, connector, x, y, drm_device))
|
|
{
|
|
drmModeFreeConnector(connector);
|
|
continue;
|
|
}
|
|
x += container_of(dcomp->base.outputs.prev, E_Output,
|
|
link)->current->w;
|
|
}
|
|
drmModeFreeConnector(connector);
|
|
}
|
|
|
|
if (wl_list_empty(&dcomp->base.outputs))
|
|
{
|
|
drmModeFreeResources(res);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
drmModeFreeResources(res);
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_output_create(E_Drm_Compositor *dcomp, drmModeRes *res, drmModeConnector *conn, int x, int y, struct udev_device *drm_device)
|
|
{
|
|
E_Drm_Output *output;
|
|
E_Drm_Output_Mode *mode, *next;
|
|
drmModeEncoder *encoder;
|
|
int i = 0, ret = 0;
|
|
unsigned int hdl, stride;
|
|
|
|
if (!(encoder = drmModeGetEncoder(dcomp->drm.fd, conn->encoders[0])))
|
|
return EINA_FALSE;
|
|
|
|
for (i = 0; i < res->count_crtcs; i++)
|
|
{
|
|
if ((encoder->possible_crtcs & (1 << i)) &&
|
|
!(dcomp->crtc_alloc & (1 << res->crtcs[i])))
|
|
break;
|
|
}
|
|
if (i == res->count_crtcs)
|
|
{
|
|
drmModeFreeEncoder(encoder);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
if (!(output = malloc(sizeof(E_Drm_Output))))
|
|
{
|
|
drmModeFreeEncoder(encoder);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
memset(output, 0, sizeof(E_Drm_Output));
|
|
|
|
output->fb_id[0] = -1;
|
|
output->fb_id[1] = -1;
|
|
output->base.subpixel = e_drm_output_subpixel_convert(conn->subpixel);
|
|
output->base.make = "unknown";
|
|
output->base.model = "unknown";
|
|
wl_list_init(&output->base.modes);
|
|
|
|
output->crtc_id = res->crtcs[i];
|
|
dcomp->crtc_alloc |= (1 << output->crtc_id);
|
|
output->conn_id = conn->connector_id;
|
|
dcomp->conn_alloc |= (1 << output->conn_id);
|
|
|
|
output->orig_crtc = drmModeGetCrtc(dcomp->drm.fd, output->crtc_id);
|
|
drmModeFreeEncoder(encoder);
|
|
|
|
for (i = 0; i < conn->count_modes; i++)
|
|
{
|
|
if (!e_drm_output_add_mode(output, &conn->modes[i]))
|
|
goto efree;
|
|
}
|
|
|
|
if (conn->count_modes == 0)
|
|
{
|
|
if (!e_drm_output_add_mode(output, &builtin_mode))
|
|
goto efree;
|
|
}
|
|
|
|
mode = container_of(output->base.modes.next, E_Drm_Output_Mode, base.link);
|
|
output->base.current = &mode->base;
|
|
mode->base.flags = (WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED);
|
|
|
|
glGenRenderbuffers(2, output->rbo);
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
|
|
output->bo[i] =
|
|
gbm_bo_create(dcomp->gbm, output->base.current->w,
|
|
output->base.current->h, GBM_BO_FORMAT_XRGB8888,
|
|
(GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING));
|
|
if (!output->bo[i]) goto ebuffs;
|
|
output->image[i] =
|
|
dcomp->base.create_image(dcomp->base.egl_display, NULL,
|
|
EGL_NATIVE_PIXMAP_KHR, output->bo[i], NULL);
|
|
if (!output->image[i]) goto ebuffs;
|
|
dcomp->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
|
|
output->image[i]);
|
|
stride = gbm_bo_get_pitch(output->bo[i]);
|
|
hdl = gbm_bo_get_handle(output->bo[i]).u32;
|
|
ret = drmModeAddFB(dcomp->drm.fd, output->base.current->w,
|
|
output->base.current->h, 24, 32, stride, hdl,
|
|
&output->fb_id[i]);
|
|
if (ret) goto ebuffs;
|
|
}
|
|
|
|
output->current = 0;
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
|
GL_RENDERBUFFER, output->rbo[output->current]);
|
|
ret = drmModeSetCrtc(dcomp->drm.fd, output->crtc_id,
|
|
output->fb_id[output->current ^ 1], 0, 0,
|
|
&output->conn_id, 1, &mode->info);
|
|
if (ret) goto efb;
|
|
|
|
/* TODO: backlight init */
|
|
|
|
e_output_init(&output->base, &dcomp->base, x, y,
|
|
conn->mmWidth, conn->mmHeight, 0);
|
|
|
|
wl_list_insert(dcomp->base.outputs.prev, &output->base.link);
|
|
|
|
output->scanout_buffer_destroy_listener.notify =
|
|
e_drm_output_scanout_buffer_destroy;
|
|
output->pending_scanout_buffer_destroy_listener.notify =
|
|
e_drm_output_pending_scanout_buffer_destroy;
|
|
|
|
output->pending_fs_surf_fb_id = 0;
|
|
output->base.repaint = e_drm_output_repaint;
|
|
output->base.destroy = e_drm_output_destroy;
|
|
output->base.assign_planes = e_drm_output_assign_planes;
|
|
output->base.set_dpms = e_drm_output_set_dpms;
|
|
|
|
return EINA_TRUE;
|
|
|
|
efb:
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
|
GL_RENDERBUFFER, 0);
|
|
|
|
ebuffs:
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
if ((int)output->fb_id[i] != -1)
|
|
drmModeRmFB(dcomp->drm.fd, output->fb_id[i]);
|
|
if (output->image[i])
|
|
dcomp->base.destroy_image(dcomp->base.egl_display, output->image[i]);
|
|
if (output->bo[i]) gbm_bo_destroy(output->bo[i]);
|
|
}
|
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
glDeleteRenderbuffers(2, output->rbo);
|
|
|
|
efree:
|
|
wl_list_for_each_safe(mode, next, &output->base.modes, base.link)
|
|
{
|
|
wl_list_remove(&mode->base.link);
|
|
free(mode);
|
|
}
|
|
drmModeFreeCrtc(output->orig_crtc);
|
|
dcomp->crtc_alloc &= ~(1 << output->crtc_id);
|
|
dcomp->conn_alloc &= ~(1 << output->conn_id);
|
|
free(output);
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static void
|
|
_outputs_update(E_Drm_Compositor *dcomp, struct udev_device *drm_device)
|
|
{
|
|
drmModeConnector *conn;
|
|
drmModeRes *res;
|
|
E_Drm_Output *doutput, *next;
|
|
int x = 0, y = 0;
|
|
int xo = 0, yo = 0;
|
|
unsigned int connected = 0, disconnects = 0;
|
|
int i = 0;
|
|
|
|
if (!(res = drmModeGetResources(dcomp->drm.fd)))
|
|
return;
|
|
|
|
for (i = 0; i < res->count_connectors; i++)
|
|
{
|
|
int conn_id;
|
|
|
|
conn_id = res->connectors[i];
|
|
if (!(conn = drmModeGetConnector(dcomp->drm.fd, conn_id)))
|
|
continue;
|
|
if (conn->connection != DRM_MODE_CONNECTED)
|
|
{
|
|
drmModeFreeConnector(conn);
|
|
continue;
|
|
}
|
|
connected |= (1 << conn_id);
|
|
if (!(dcomp->conn_alloc & (1 << conn_id)))
|
|
{
|
|
E_Output *last;
|
|
|
|
last = container_of(dcomp->base.outputs.prev, E_Output, link);
|
|
if (!wl_list_empty(&dcomp->base.outputs))
|
|
x = last->x + last->current->w;
|
|
else
|
|
x = 0;
|
|
y = 0;
|
|
_output_create(dcomp, res, conn, x, y, drm_device);
|
|
}
|
|
drmModeFreeConnector(conn);
|
|
}
|
|
drmModeFreeResources(res);
|
|
|
|
if ((disconnects = dcomp->conn_alloc & ~connected))
|
|
{
|
|
wl_list_for_each_safe(doutput, next, &dcomp->base.outputs, base.link)
|
|
{
|
|
if ((xo != 0) || (yo != 0))
|
|
e_output_move(&doutput->base, doutput->base.x - xo,
|
|
doutput->base.y - yo);
|
|
if (disconnects & (1 << doutput->conn_id))
|
|
{
|
|
disconnects &= ~(1 << doutput->conn_id);
|
|
xo += doutput->base.current->w;
|
|
e_drm_output_destroy(&doutput->base);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dcomp->conn_alloc == 0)
|
|
wl_display_terminate(dcomp->base.display);
|
|
}
|
|
|
|
static Eina_Bool
|
|
_udev_event_is_hotplug(E_Drm_Compositor *dcomp, struct udev_device *dev)
|
|
{
|
|
const char *snum, *val;
|
|
|
|
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
snum = udev_device_get_sysnum(dev);
|
|
if ((!snum) || (atoi(snum) != dcomp->drm.id))
|
|
return EINA_FALSE;
|
|
|
|
if (!(val = udev_device_get_property_value(dev, "HOTPLUG")))
|
|
return EINA_FALSE;
|
|
|
|
if (!strcmp(val, "1")) return EINA_TRUE;
|
|
|
|
return EINA_FALSE;
|
|
}
|