2 #include "e_mod_main.h"
5 e_drm_output_subpixel_convert(int value)
7 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
11 case DRM_MODE_SUBPIXEL_NONE:
12 return WL_OUTPUT_SUBPIXEL_NONE;
13 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
14 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
15 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
16 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
17 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
18 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
19 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
20 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
21 case DRM_MODE_SUBPIXEL_UNKNOWN:
23 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
28 e_drm_output_add_mode(E_Drm_Output *output, drmModeModeInfo *info)
30 E_Drm_Output_Mode *mode;
32 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
34 if (!(mode = malloc(sizeof(E_Drm_Output_Mode))))
38 mode->base.w = info->hdisplay;
39 mode->base.h = info->vdisplay;
40 mode->base.refresh = info->vrefresh;
43 wl_list_insert(output->base.modes.prev, &mode->base.link);
49 e_drm_output_set_modes(E_Drm_Compositor *dcomp)
52 E_Drm_Output_Mode *mode;
55 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
57 wl_list_for_each(output, &dcomp->base.outputs, base.link)
59 mode = (E_Drm_Output_Mode *)output->base.current;
60 ret = drmModeSetCrtc(dcomp->drm.fd, output->crtc_id,
61 output->fb_id[output->current ^ 1], 0, 0,
62 &output->conn_id, 1, &mode->info);
64 printf("Failed to set drm mode: %m\n");
69 e_drm_output_scanout_buffer_destroy(struct wl_listener *listener, void *data __UNUSED__)
73 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
75 output = container_of(listener, E_Drm_Output, scanout_buffer_destroy_listener);
76 output->scanout_buffer = NULL;
77 if (!output->pending_scanout_buffer)
78 e_compositor_schedule_repaint(output->base.compositor);
82 e_drm_output_pending_scanout_buffer_destroy(struct wl_listener *listener, void *data __UNUSED__)
86 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
88 output = container_of(listener, E_Drm_Output,
89 pending_scanout_buffer_destroy_listener);
90 output->pending_scanout_buffer = NULL;
91 e_compositor_schedule_repaint(output->base.compositor);
95 e_drm_output_repaint(E_Output *base, pixman_region32_t *damage)
98 E_Drm_Compositor *dcomp;
101 unsigned int fb_id = 0;
104 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
106 output = (E_Drm_Output *)base;
107 dcomp = (E_Drm_Compositor *)output->base.compositor;
109 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
110 GL_RENDERBUFFER, output->rbo[output->current]);
111 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
114 e_drm_output_prepare_scanout_surface(output);
116 wl_list_for_each_reverse(es, &dcomp->base.surfaces, link)
117 e_surface_draw(es, &output->base, damage);
121 output->current ^= 1;
123 if (output->pending_fs_surf_fb_id != 0)
124 fb_id = output->pending_fs_surf_fb_id;
126 fb_id = output->fb_id[output->current ^ 1];
128 if (drmModePageFlip(dcomp->drm.fd, output->crtc_id, fb_id,
129 DRM_MODE_PAGE_FLIP_EVENT, output) < 0)
132 wl_list_for_each(sprite, &dcomp->sprites, link)
134 unsigned int flags = 0;
137 vbl.request.type = (DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT);
138 vbl.request.sequence = 1;
139 if (!e_sprite_crtc_supported(base, sprite->possible_crtcs))
141 ret = drmModeSetPlane(dcomp->drm.fd, sprite->plane_id, output->crtc_id,
142 sprite->pending_fb_id, flags, sprite->dx,
143 sprite->dy, sprite->dw, sprite->dh, sprite->sx,
144 sprite->sy, sprite->sw, sprite->sh);
146 printf("Setplane Failed: %s\n", strerror(errno));
148 vbl.request.signal = (unsigned long)sprite;
149 ret = drmWaitVBlank(dcomp->drm.fd, &vbl);
151 printf("VBlank event request failed: %s\n", strerror(errno));
156 e_drm_output_destroy(E_Output *base)
158 E_Drm_Output *output;
159 E_Drm_Compositor *dcomp;
160 drmModeCrtcPtr ocrtc;
163 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
165 output = (E_Drm_Output *)base;
166 dcomp = (E_Drm_Compositor *)output->base.compositor;
167 ocrtc = output->orig_crtc;
169 /* TODO: backlight */
170 /* if (base->backlight) */
172 e_drm_output_set_cursor(&output->base, NULL);
174 drmModeSetCrtc(dcomp->drm.fd, ocrtc->crtc_id, ocrtc->buffer_id,
175 ocrtc->x, ocrtc->y, &output->conn_id, 1, &ocrtc->mode);
176 drmModeFreeCrtc(ocrtc);
178 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
180 glBindRenderbuffer(GL_RENDERBUFFER, 0);
181 glDeleteRenderbuffers(2, output->rbo);
183 for (i = 0; i < 2; i++)
185 drmModeRmFB(dcomp->drm.fd, output->fb_id[i]);
186 dcomp->base.destroy_image(dcomp->base.egl_display, output->image[i]);
187 gbm_bo_destroy(output->bo[i]);
190 dcomp->crtc_alloc &= ~(1 << output->crtc_id);
191 dcomp->conn_alloc &= ~(1 << output->conn_id);
193 e_output_destroy(&output->base);
194 wl_list_remove(&output->base.link);
200 e_drm_output_assign_planes(E_Output *base)
204 pixman_region32_t overlap, soverlap;
207 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
209 comp = base->compositor;
210 pixman_region32_init(&overlap);
211 wl_list_for_each(es, &comp->surfaces, link)
213 pixman_region32_init(&soverlap);
214 pixman_region32_intersect(&soverlap, &overlap, &es->transform.box);
215 dev = (E_Input_Device *)comp->input_device;
216 if (es == dev->sprite)
218 e_drm_output_set_cursor_region(base, dev, &soverlap);
220 pixman_region32_union(&overlap, &overlap, &es->transform.box);
222 else if (!e_drm_output_prepare_overlay_surface(base, es, &soverlap))
224 pixman_region32_fini(&es->damage);
225 pixman_region32_init(&es->damage);
228 pixman_region32_union(&overlap, &overlap, &es->transform.box);
230 pixman_region32_fini(&soverlap);
232 pixman_region32_fini(&overlap);
234 e_drm_output_disable_sprites(base);
238 e_drm_output_set_dpms(E_Output *base, E_Dpms_Level level)
240 E_Drm_Output *output;
242 E_Drm_Compositor *dcomp;
243 drmModeConnectorPtr conn;
244 drmModePropertyPtr prop;
246 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
248 output = (E_Drm_Output *)base;
249 comp = base->compositor;
250 dcomp = (E_Drm_Compositor *)comp;
252 if (!(conn = drmModeGetConnector(dcomp->drm.fd, output->conn_id)))
254 if (!(prop = e_drm_output_get_property(dcomp->drm.fd, conn, "DPMS")))
256 drmModeFreeConnector(conn);
259 drmModeConnectorSetProperty(dcomp->drm.fd, conn->connector_id,
260 prop->prop_id, level);
261 drmModeFreeProperty(prop);
262 drmModeFreeConnector(conn);
266 e_drm_output_prepare_scanout_surface(E_Drm_Output *output)
268 E_Drm_Compositor *dcomp;
272 unsigned int fb_id = 0;
275 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
277 dcomp = (E_Drm_Compositor *)output->base.compositor;
278 es = container_of(dcomp->base.surfaces.next, E_Surface, link);
280 /* Need to verify output->region contained in surface opaque
281 * region. Or maybe just that format doesn't have alpha. */
284 if ((es->geometry.x != output->base.x) ||
285 (es->geometry.y != output->base.y) ||
286 (es->geometry.w != output->base.current->w) ||
287 (es->geometry.h != output->base.current->h) ||
288 (es->transform.enabled) || (es->image == EGL_NO_IMAGE_KHR))
291 bo = gbm_bo_create_from_egl_image(dcomp->gbm, dcomp->base.egl_display,
292 es->image, es->geometry.w,
293 es->geometry.h, GBM_BO_USE_SCANOUT);
294 hdl = gbm_bo_get_handle(bo).s32;
295 stride = gbm_bo_get_pitch(bo);
299 if (hdl == 0) return EINA_FALSE;
301 ret = drmModeAddFB(dcomp->drm.fd, output->base.current->w,
302 output->base.current->h, 24, 32, stride, hdl, &fb_id);
303 if (ret) return EINA_FALSE;
305 output->pending_fs_surf_fb_id = fb_id;
307 output->pending_scanout_buffer = es->buffer;
308 output->pending_scanout_buffer->busy_count++;
310 wl_signal_add(&output->pending_scanout_buffer->resource.destroy_signal,
311 &output->pending_scanout_buffer_destroy_listener);
313 pixman_region32_fini(&es->damage);
314 pixman_region32_init(&es->damage);
320 e_drm_output_disable_sprites(E_Output *base)
323 E_Drm_Compositor *dcomp;
324 E_Drm_Output *output;
328 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
330 comp = base->compositor;
331 dcomp = (E_Drm_Compositor *)comp;
332 output = (E_Drm_Output *)base;
334 wl_list_for_each(s, &dcomp->sprites, link)
336 if (s->pending_fb_id) continue;
337 ret = drmModeSetPlane(dcomp->drm.fd, s->plane_id, output->crtc_id,
338 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
340 printf("Failed to disable plane: %s\n", strerror(errno));
341 drmModeRmFB(dcomp->drm.fd, s->fb_id);
343 s->pending_surface = NULL;
345 s->pending_fb_id = 0;
349 EINTERN drmModePropertyPtr
350 e_drm_output_get_property(int fd, drmModeConnectorPtr conn, const char *name)
352 drmModePropertyPtr props;
355 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
357 for (i = 0; i < conn->count_props; i++)
359 if (!(props = drmModeGetProperty(fd, conn->props[i])))
361 if (!strcmp(props->name, name)) return props;
362 drmModeFreeProperty(props);
369 e_drm_output_prepare_overlay_surface(E_Output *base, E_Surface *es, pixman_region32_t *overlap)
372 E_Drm_Compositor *dcomp;
374 Eina_Bool found = EINA_FALSE;
377 unsigned int fb_id = 0;
378 unsigned int hdls[4], pitches[4], offsets[4];
380 pixman_region32_t drect, srect;
384 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
386 comp = base->compositor;
387 dcomp = (E_Drm_Compositor *)comp;
389 if (dcomp->sprites_broken) return -1;
390 if (e_surface_is_primary(comp, es)) return -1;
391 if (es->image == EGL_NO_IMAGE_KHR) return -1;
393 if (!e_drm_output_surface_transform_supported(es))
395 if (!e_drm_output_surface_overlap_supported(base, overlap))
398 wl_list_for_each(s, &dcomp->sprites, link)
400 if (!e_sprite_crtc_supported(base, s->possible_crtcs))
402 if (!s->pending_fb_id)
409 if (!found) return -1;
411 bo = gbm_bo_create_from_egl_image(dcomp->gbm, dcomp->base.egl_display,
412 es->image, es->geometry.w,
413 es->geometry.h, GBM_BO_USE_SCANOUT);
414 format = gbm_bo_get_format(bo);
415 hdl = gbm_bo_get_handle(bo).s32;
416 stride = gbm_bo_get_pitch(bo);
420 if (!e_drm_output_surface_format_supported(s, format))
429 ret = drmModeAddFB2(dcomp->drm.fd, es->geometry.w, es->geometry.h,
430 format, hdls, pitches, offsets, &fb_id, 0);
433 dcomp->sprites_broken = EINA_TRUE;
437 if ((s->surface) && (s->surface != es))
442 pixman_region32_fini(&os->damage);
443 pixman_region32_init_rect(&os->damage, os->geometry.x, os->geometry.y,
444 os->geometry.w, os->geometry.h);
447 s->pending_fb_id = fb_id;
448 s->pending_surface = es;
449 es->buffer->busy_count++;
451 pixman_region32_init(&drect);
452 pixman_region32_intersect(&drect, &es->transform.box, &base->region);
453 pixman_region32_translate(&drect, -base->x, -base->y);
455 box = pixman_region32_extents(&drect);
458 s->dw = (box->x2 - box->x1);
459 s->dh = (box->y2 - box->y1);
460 pixman_region32_fini(&drect);
462 pixman_region32_init(&srect);
463 pixman_region32_intersect(&srect, &es->transform.box, &base->region);
464 pixman_region32_translate(&srect, -es->geometry.x, -es->geometry.y);
466 box = pixman_region32_extents(&srect);
467 s->sx = box->x1 << 16;
468 s->sy = box->y1 << 16;
469 s->sw = (box->x2 - box->x1) << 16;
470 s->sh = (box->y2 - box->y1) << 16;
471 pixman_region32_fini(&srect);
473 wl_signal_add(&es->buffer->resource.destroy_signal,
474 &s->pending_destroy_listener);
480 e_drm_output_surface_transform_supported(E_Surface *es)
482 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
484 if ((es) && (es->transform.enabled)) return EINA_TRUE;
489 e_drm_output_surface_overlap_supported(E_Output *base __UNUSED__, pixman_region32_t *overlap)
491 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
493 if (pixman_region32_not_empty(overlap)) return EINA_TRUE;
498 e_drm_output_surface_format_supported(E_Sprite *s, unsigned int format)
502 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
504 for (i = 0; i < s->format_count; i++)
505 if (s->formats[i] == format) return EINA_TRUE;
511 e_drm_output_set_cursor_region(E_Output *output, E_Input_Device *device, pixman_region32_t *overlap)
513 pixman_region32_t cregion;
514 Eina_Bool prior = EINA_FALSE;
516 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
518 if (!device->sprite) return;
519 pixman_region32_init(&cregion);
520 pixman_region32_intersect(&cregion, &device->sprite->transform.box,
522 if (!pixman_region32_not_empty(&cregion))
524 e_drm_output_set_cursor(output, NULL);
528 prior = device->hw_cursor;
529 if ((pixman_region32_not_empty(overlap)) ||
530 (!e_drm_output_set_cursor(output, device)))
534 e_surface_damage(device->sprite);
535 e_drm_output_set_cursor(output, NULL);
537 device->hw_cursor = EINA_FALSE;
541 if (!prior) e_surface_damage_below(device->sprite);
542 pixman_region32_fini(&device->sprite->damage);
543 pixman_region32_init(&device->sprite->damage);
544 device->hw_cursor = EINA_TRUE;
548 pixman_region32_fini(&cregion);
552 e_drm_output_set_cursor(E_Output *output, E_Input_Device *device)
554 E_Drm_Output *doutput;
555 E_Drm_Compositor *dcomp;
560 DLOGFN(__FILE__, __LINE__, __FUNCTION__);
562 doutput = (E_Drm_Output *)output;
563 dcomp = (E_Drm_Compositor *)doutput->base.compositor;
567 drmModeSetCursor(dcomp->drm.fd, doutput->crtc_id, 0, 0, 0);
571 if (device->sprite->image == EGL_NO_IMAGE_KHR) return EINA_FALSE;
573 if ((device->sprite->geometry.w > 64) ||
574 (device->sprite->geometry.h > 64))
577 bo = gbm_bo_create_from_egl_image(dcomp->gbm, dcomp->base.egl_display,
578 device->sprite->image, 64, 64,
579 GBM_BO_USE_CURSOR_64X64);
580 if (!bo) return EINA_FALSE;
582 hdl = gbm_bo_get_handle(bo).s32;
583 stride = gbm_bo_get_pitch(bo);
586 if (stride != (64 * 4)) return EINA_FALSE;
588 if ((ret = drmModeSetCursor(dcomp->drm.fd, doutput->crtc_id, hdl, 64, 64)))
590 drmModeSetCursor(dcomp->drm.fd, doutput->crtc_id, 0, 0, 0);
594 ret = drmModeMoveCursor(dcomp->drm.fd, doutput->crtc_id,
595 device->sprite->geometry.x - doutput->base.x,
596 device->sprite->geometry.y - doutput->base.y);
599 drmModeSetCursor(dcomp->drm.fd, doutput->crtc_id, 0, 0, 0);