[PATCH weston 2/2 v3] clients/simple-egl-lease: A demo client for DRM leases
Marius Vlad
marius-cristian.vlad at nxp.com
Wed Feb 21 14:49:05 UTC 2018
Heavily inspired by kmscube and simple-egl. Uses legacy page-flipping and
triangle shaders from simple-egl.
Signed-off-by: Marius Vlad <marius-cristian.vlad at nxp.com>
---
Makefile.am | 11 +
clients/simple-egl-lease.c | 887 +++++++++++++++++++++++++++++++++++++++++++++
clients/simple-egl-lease.h | 99 +++++
configure.ac | 17 +
4 files changed, 1014 insertions(+)
create mode 100644 clients/simple-egl-lease.c
create mode 100644 clients/simple-egl-lease.h
diff --git a/Makefile.am b/Makefile.am
index 439fa73..c2bef07 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -641,6 +641,17 @@ weston_simple_dmabuf_v4l_CFLAGS = $(AM_CFLAGS) $(SIMPLE_DMABUF_V4L_CLIENT_CFLAGS
weston_simple_dmabuf_v4l_LDADD = $(SIMPLE_DMABUF_V4L_CLIENT_LIBS) libshared.la
endif
+if BUILD_SIMPLE_EGL_LEASE_CLIENTS
+demo_clients += weston-simple-egl-lease
+weston_simple_egl_lease_SOURCES = clients/simple-egl-lease.c
+nodist_weston_simple_egl_lease_SOURCES = protocol/drm-lease-unstable-v1-protocol.c \
+ protocol/drm-lease-unstable-v1-client-protocol.h
+weston_simple_egl_lease_CFLAGS = $(AM_CFLAGS) $(SIMPLE_EGL_LEASE_CLIENT_CFLAGS) \
+ $(LIBDRM_CFLAGS)
+weston_simple_egl_lease_LDADD = $(SIMPLE_EGL_LEASE_CLIENT_LIBS) $(LIBDRM_LIBS) \
+ $(GBM_LIBS) -lm
+endif
+
noinst_LTLIBRARIES += libtoytoolkit.la
libtoytoolkit_la_SOURCES = \
diff --git a/clients/simple-egl-lease.c b/clients/simple-egl-lease.c
new file mode 100644
index 0000000..8922e57
--- /dev/null
+++ b/clients/simple-egl-lease.c
@@ -0,0 +1,887 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Adapted from kmscube and simple-egl. No atomic support atm.
+ *
+ */
+
+#include "config.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <math.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <wayland-client.h>
+
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "drm-lease-unstable-v1-client-protocol.h"
+
+#include <gbm.h>
+#include <drm_fourcc.h>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "simple-egl-lease.h"
+
+static volatile uint8_t sig_recv = 0;
+
+static const GLfloat verts[3][2] = {
+ { -0.5, -0.5 },
+ { 0.5, -0.5 },
+ { 0, 0.5 }
+};
+
+static const GLfloat colors[3][3] = {
+ { 1, 0, 0 },
+ { 0, 1, 0 },
+ { 0, 0, 1 }
+};
+
+GLfloat rotation[4][4] = {
+ { 1, 0, 0, 0 },
+ { 0, 1, 0, 0 },
+ { 0, 0, 1, 0 },
+ { 0, 0, 0, 1 }
+};
+
+static const char *vertex_shader_source =
+ "uniform mat4 rotation;\n"
+ "attribute vec4 pos;\n"
+ "attribute vec4 color;\n"
+ "varying vec4 v_color;\n"
+ "void main() {\n"
+ " gl_Position = rotation * pos;\n"
+ " v_color = color;\n"
+ "}\n";
+
+static const char *fragment_shader_source =
+ "precision mediump float;\n"
+ "varying vec4 v_color;\n"
+ "void main() {\n"
+ " gl_FragColor = v_color;\n"
+ "}\n";
+
+static struct gbm *
+init_gbm(int drm_fd, int w, int h)
+{
+ struct gbm *gbm = calloc(1, sizeof(*gbm));
+
+ gbm->dev = gbm_create_device(drm_fd);
+
+ gbm->surface = gbm_surface_create(gbm->dev, w, h, GBM_FORMAT_XRGB8888,
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+ if (!gbm->surface) {
+ printf("failed to create gbm surface\n");
+ return NULL;
+ }
+
+ gbm->width = w;
+ gbm->height = h;
+
+ return gbm;
+}
+
+static int
+init_egl(struct egl *egl, const struct gbm *gbm)
+{
+ EGLint major, minor, n;
+
+ static const EGLint context_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ static const EGLint config_attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 1,
+ EGL_GREEN_SIZE, 1,
+ EGL_BLUE_SIZE, 1,
+ EGL_ALPHA_SIZE, 0,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+
+#define get_proc(name) do { \
+ egl->name = (void *)eglGetProcAddress(#name); \
+ } while (0)
+
+ get_proc(eglGetPlatformDisplayEXT);
+
+ if (egl->eglGetPlatformDisplayEXT) {
+ egl->display = egl->eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR,
+ gbm->dev, NULL);
+ } else {
+ egl->display = eglGetDisplay((void *)gbm->dev);
+ }
+
+ if (!eglInitialize(egl->display, &major, &minor)) {
+ printf("failed to initialize\n");
+ return -1;
+ }
+
+ printf("Using display %p with EGL version %d.%d\n",
+ egl->display, major, minor);
+
+ printf("===================================\n");
+ printf("EGL information:\n");
+ printf(" version: \"%s\"\n", eglQueryString(egl->display, EGL_VERSION));
+ printf(" vendor: \"%s\"\n", eglQueryString(egl->display, EGL_VENDOR));
+ printf(" extensions: \"%s\"\n", eglQueryString(egl->display, EGL_EXTENSIONS));
+ printf("===================================\n");
+
+ if (!eglBindAPI(EGL_OPENGL_ES_API)) {
+ printf("failed to bind api EGL_OPENGL_ES_API\n");
+ return -1;
+ }
+
+ if (!eglChooseConfig(egl->display, config_attribs, &egl->config, 1, &n) || n != 1) {
+ printf("failed to choose config: %d\n", n);
+ return -1;
+ }
+
+ egl->context = eglCreateContext(egl->display, egl->config,
+ EGL_NO_CONTEXT, context_attribs);
+ if (egl->context == NULL) {
+ printf("failed to create context\n");
+ return -1;
+ }
+
+ egl->surface = eglCreateWindowSurface(egl->display, egl->config,
+ (EGLNativeWindowType)gbm->surface, NULL);
+ if (egl->surface == EGL_NO_SURFACE) {
+ printf("failed to create egl surface\n");
+ return -1;
+ }
+
+ /* connect the context to the surface */
+ eglMakeCurrent(egl->display, egl->surface, egl->surface, egl->context);
+
+ printf("OpenGL ES 2.x information:\n");
+ printf(" version: \"%s\"\n", glGetString(GL_VERSION));
+ printf(" shading language version: \"%s\"\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
+ printf(" vendor: \"%s\"\n", glGetString(GL_VENDOR));
+ printf(" renderer: \"%s\"\n", glGetString(GL_RENDERER));
+ printf(" extensions: \"%s\"\n", glGetString(GL_EXTENSIONS));
+ printf("===================================\n");
+
+ return 0;
+}
+
+static int
+create_program(const char *vs_src, const char *fs_src)
+{
+ GLuint vertex_shader, fragment_shader, program;
+ GLint ret;
+
+ vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+
+ glShaderSource(vertex_shader, 1, &vs_src, NULL);
+ glCompileShader(vertex_shader);
+
+ glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret);
+ if (!ret) {
+ char *log;
+
+ printf("vertex shader compilation failed!:\n");
+ glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &ret);
+ if (ret > 1) {
+ log = malloc(ret);
+ glGetShaderInfoLog(vertex_shader, ret, NULL, log);
+ printf("%s", log);
+ }
+
+ return -1;
+ }
+
+ fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+ glShaderSource(fragment_shader, 1, &fs_src, NULL);
+ glCompileShader(fragment_shader);
+
+ glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret);
+ if (!ret) {
+ char *log;
+
+ printf("fragment shader compilation failed!:\n");
+ glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &ret);
+
+ if (ret > 1) {
+ log = malloc(ret);
+ glGetShaderInfoLog(fragment_shader, ret, NULL, log);
+ printf("%s", log);
+ }
+
+ return -1;
+ }
+
+ program = glCreateProgram();
+
+ glAttachShader(program, vertex_shader);
+ glAttachShader(program, fragment_shader);
+
+ return program;
+}
+
+static int
+link_program(unsigned program)
+{
+ GLint ret;
+
+ glLinkProgram(program);
+
+ glGetProgramiv(program, GL_LINK_STATUS, &ret);
+ if (!ret) {
+ char *log;
+
+ printf("program linking failed!:\n");
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &ret);
+
+ if (ret > 1) {
+ log = malloc(ret);
+ glGetProgramInfoLog(program, ret, NULL, log);
+ printf("%s", log);
+ }
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+registry_handle_global(void *data, struct wl_registry *registry,
+ uint32_t id, const char *interface, uint32_t version)
+{
+ (void) version;
+ struct display *d = data;
+
+ /* test if the interface advertise the leases feat. */
+ if (!strcmp(interface, "zwp_kms_lease_manager_v1")) {
+ d->lease_manager = wl_registry_bind(registry, id,
+ &zwp_kms_lease_manager_v1_interface, 1);
+ fprintf(stdout, "zwp_kms_lease_manager_v1_interface bound\n");
+ }
+}
+
+static void
+registry_handle_global_remove(void *data, struct wl_registry *registry,
+ uint32_t name)
+{
+ (void) data;
+ (void) name;
+ (void) registry;
+}
+
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ registry_handle_global_remove
+};
+
+static void lease_created(void *data,
+ struct zwp_kms_lease_request_v1 *zwp_kms_lease_request_v1,
+ int32_t fd, uint32_t id)
+{
+ (void) data;
+ (void) zwp_kms_lease_request_v1;
+
+ struct display *display = (struct display *) data;
+ display->drm_display.leased_fd = fd;
+ display->drm_display.lessee_id = id;
+ fprintf(stdout, "Lease created with fd %d, id %u\n", fd, id);
+}
+
+static void lease_failed(void *data,
+ struct zwp_kms_lease_request_v1 *zwp_kms_lease_request_v1)
+{
+ (void) data;
+ (void) zwp_kms_lease_request_v1;
+
+ fprintf(stdout, "Lease failed\n");
+}
+
+static void lease_revoked(void *data,
+ struct zwp_kms_lease_request_v1 *zwp_kms_lease_request_v1)
+{
+ (void) data;
+ (void) zwp_kms_lease_request_v1;
+
+ fprintf(stdout, "Lease revoked\n");
+}
+
+static const struct zwp_kms_lease_request_v1_listener lease_request_interface = {
+ lease_created,
+ lease_failed,
+ lease_revoked,
+};
+
+static struct display *
+wl_create_display(void)
+{
+ struct display *display;
+
+ display = calloc(1, sizeof(*display));
+ if (display == NULL) {
+ fprintf(stderr, "out of memory\n");
+ exit(EXIT_FAILURE);
+ }
+ display->display = wl_display_connect(NULL);
+ if (display->display == NULL) {
+ free(display);
+ return NULL;
+ }
+
+ display->registry = wl_display_get_registry(display->display);
+ wl_registry_add_listener(display->registry, ®istry_listener, display);
+
+ wl_display_roundtrip(display->display);
+ if (display->lease_manager == NULL) {
+ return NULL;
+ }
+
+ display->lease_request =
+ zwp_kms_lease_manager_v1_create_lease_req(display->lease_manager);
+ zwp_kms_lease_request_v1_add_listener(display->lease_request,
+ &lease_request_interface,
+ display);
+
+ wl_display_roundtrip(display->display);
+ return display;
+}
+
+static void
+wl_destroy_display(struct display *display)
+{
+ if (display->lease_manager)
+ zwp_kms_lease_manager_v1_destroy(display->lease_manager);
+
+ wl_display_roundtrip(display->display);
+ wl_registry_destroy(display->registry);
+ wl_display_flush(display->display);
+ wl_display_disconnect(display->display);
+ free(display);
+}
+
+static int
+get_plane_id(uint32_t crtc_index, int drm_fd)
+{
+ drmModePlaneResPtr plane_resources;
+ uint32_t i, j;
+ int ret = -EINVAL;
+ int found_primary = 0;
+
+ plane_resources = drmModeGetPlaneResources(drm_fd);
+ if (!plane_resources) {
+ printf("drmModeGetPlaneResources failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ for (i = 0; (i < plane_resources->count_planes) && !found_primary; i++) {
+ uint32_t id = plane_resources->planes[i];
+ drmModePlanePtr plane = drmModeGetPlane(drm_fd, id);
+ if (!plane) {
+ printf("drmModeGetPlane(%u) failed: %s\n", id, strerror(errno));
+ continue;
+ }
+
+ if (plane->possible_crtcs & (1 << crtc_index)) {
+ drmModeObjectPropertiesPtr props =
+ drmModeObjectGetProperties(drm_fd, id, DRM_MODE_OBJECT_PLANE);
+
+ /* primary or not, this plane is good enough to use: */
+ ret = id;
+
+ for (j = 0; j < props->count_props; j++) {
+ drmModePropertyPtr p =
+ drmModeGetProperty(drm_fd, props->props[j]);
+
+ if ((strcmp(p->name, "type") == 0) &&
+ (props->prop_values[j] == DRM_PLANE_TYPE_PRIMARY)) {
+ /* found our primary plane, lets use that: */
+ found_primary = 1;
+ }
+
+ drmModeFreeProperty(p);
+ }
+ drmModeFreeObjectProperties(props);
+ }
+ drmModeFreePlane(plane);
+ }
+ drmModeFreePlaneResources(plane_resources);
+
+ return ret;
+}
+
+static void
+create_wl_lease(struct display *display,
+ const struct drm_resources *drm_resources)
+{
+ zwp_kms_lease_request_v1_add_connector(display->lease_request,
+ drm_resources->connector_id);
+ zwp_kms_lease_request_v1_add_crtc(display->lease_request,
+ drm_resources->crtc_id);
+ zwp_kms_lease_request_v1_add_plane(display->lease_request,
+ drm_resources->plane_id);
+
+ zwp_kms_lease_request_v1_create(display->lease_request);
+
+ wl_display_dispatch(display->display);
+ wl_display_roundtrip(display->display);
+}
+
+static uint32_t
+get_crtc_index(const drmModeRes *resources, uint32_t crtc_id)
+{
+ int i;
+ uint32_t crtc_index = 0;
+
+ for (i = 0; i < resources->count_crtcs; i++) {
+ if (resources->crtcs[i] == crtc_id) {
+ crtc_index = i;
+ break;
+ }
+ }
+
+ return crtc_index;
+}
+
+static int
+get_mode(struct drm_resources *drm_resources, const drmModeConnector *connector)
+{
+ int i, area;
+
+ for (i = 0, area = 0; i < connector->count_modes; i++) {
+ drmModeModeInfo *current_mode = &connector->modes[i];
+
+ if (current_mode->type & DRM_MODE_TYPE_PREFERRED) {
+ drm_resources->mode = current_mode;
+ }
+
+ int current_area = current_mode->hdisplay * current_mode->vdisplay;
+ if (current_area > area) {
+ drm_resources->mode = current_mode;
+ area = current_area;
+ }
+ }
+
+ if (!drm_resources->mode) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+check_wl_drm_resources(struct display *display, int drm_fd,
+ struct drm_resources *drm_resources)
+{
+ drmModeRes *resources = drmModeGetResources(drm_fd);
+ drmModeConnector *connector = NULL;
+ drmModeEncoder *encoder = NULL;
+
+ int i, j;
+ int lease_created = -1;
+
+ /*
+ * try to determine which of the connectors is OK to use as a lease.
+ */
+ for (i = 0; i < resources->count_connectors; i++) {
+ connector = drmModeGetConnector(drm_fd, resources->connectors[i]);
+
+ if (connector->connection == DRM_MODE_CONNECTED) {
+ drm_resources->connector_id = connector->connector_id;
+
+ for (j = 0; i < resources->count_encoders; j++) {
+ encoder = drmModeGetEncoder(drm_fd, resources->encoders[j]);
+ if (!encoder)
+ break;
+
+ if (encoder->encoder_id == connector->encoder_id) {
+
+ drm_resources->crtc_id =
+ encoder->crtc_id;
+ drm_resources->crtc_index =
+ get_crtc_index(resources, drm_resources->crtc_id);
+ drm_resources->plane_id =
+ get_plane_id(drm_resources->crtc_index, drm_fd);
+
+ if (get_mode(drm_resources, connector) < 0) {
+ drmModeFreeConnector(connector);
+ drmModeFreeEncoder(encoder);
+ drmModeFreeResources(resources);
+ goto out;
+ }
+
+ create_wl_lease(display, drm_resources);
+ if (display->drm_display.leased_fd <= 0) {
+ drmModeFreeEncoder(encoder);
+ encoder = NULL;
+ break;
+ } else {
+
+ lease_created = 0;
+ drm_resources->drm_fd =
+ display->drm_display.leased_fd;
+
+ drmModeFreeEncoder(encoder);
+ drmModeFreeResources(resources);
+ goto out;
+ }
+ }
+ }
+ }
+
+ drmModeFreeConnector(connector);
+ connector = NULL;
+ }
+
+ drmModeFreeResources(resources);
+
+out:
+ return lease_created;
+}
+
+static void
+drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
+{
+ int drm_fd = gbm_device_get_fd(gbm_bo_get_device(bo));
+ struct drm_fb *fb = data;
+
+ if (fb->fb_id)
+ drmModeRmFB(drm_fd, fb->fb_id);
+
+ free(fb);
+}
+
+static struct drm_fb *
+drm_fb_get_from_bo(struct gbm_bo *bo)
+{
+ int drm_fd = gbm_device_get_fd(gbm_bo_get_device(bo));
+ struct drm_fb *fb = gbm_bo_get_user_data(bo);
+ uint32_t width, height,
+ strides[4] = {0}, handles[4] = {0},
+ offsets[4] = {0};
+ int ret = -1;
+
+ if (fb)
+ return fb;
+
+ fb = calloc(1, sizeof *fb);
+ fb->bo = bo;
+
+ width = gbm_bo_get_width(bo);
+ height = gbm_bo_get_height(bo);
+
+
+ memcpy(handles, (uint32_t [4]) { gbm_bo_get_handle(bo).u32,0,0,0 }, 16);
+ memcpy(strides, (uint32_t [4]) { gbm_bo_get_stride(bo),0,0,0 }, 16);
+ memset(offsets, 0, 16);
+
+ ret = drmModeAddFB2(drm_fd, width, height, DRM_FORMAT_XRGB8888,
+ handles, strides, offsets, &fb->fb_id, 0);
+
+ if (ret) {
+ printf("failed to create fb: %s\n", strerror(errno));
+ free(fb);
+ return NULL;
+ }
+
+ gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
+
+ return fb;
+}
+
+static void
+draw_triangle(struct egl *egl)
+{
+ struct gl *gl = (struct gl *) egl;
+ GLfloat angle;
+ struct timeval tv;
+ uint32_t time;
+
+ gettimeofday(&tv, NULL);
+ time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+
+ angle = (time / 5) % 360 * M_PI / 180.0;
+ rotation[0][0] = cos(angle);
+ rotation[0][2] = sin(angle);
+ rotation[2][0] = -sin(angle);
+ rotation[2][2] = cos(angle);
+
+ glUniformMatrix4fv(gl->rotation_uniform, 1, GL_FALSE, (GLfloat *) rotation);
+
+ glClearColor(0.0, 0.0, 0.0, 0.5);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glVertexAttribPointer(gl->pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
+ glVertexAttribPointer(gl->col, 3, GL_FLOAT, GL_FALSE, 0, colors);
+ glEnableVertexAttribArray(gl->pos);
+ glEnableVertexAttribArray(gl->col);
+
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+
+ glDisableVertexAttribArray(gl->pos);
+ glDisableVertexAttribArray(gl->col);
+}
+
+static struct egl *
+init_triangle(const struct gbm *gbm)
+{
+ int ret;
+ struct gl *gl = calloc(1, sizeof(*gl));
+
+ ret = init_egl(&gl->egl, gbm);
+ if (ret)
+ return NULL;
+
+ gl->aspect = (GLfloat)(gbm->height) / (GLfloat)(gbm->width);
+
+ ret = create_program(vertex_shader_source, fragment_shader_source);
+ if (ret < 0)
+ return NULL;
+
+ gl->program = ret;
+
+ gl->pos = 0;
+ gl->col = 1;
+
+ glBindAttribLocation(gl->program, gl->pos, "pos");
+ glBindAttribLocation(gl->program, gl->col, "color");
+ ret = link_program(gl->program);
+ if (ret)
+ return NULL;
+
+ gl->rotation_uniform = glGetUniformLocation(gl->program, "rotation");
+ glUseProgram(gl->program);
+ glViewport(0, 0, gbm->width, gbm->height);
+
+ gl->egl.draw = draw_triangle;
+ return &gl->egl;
+}
+
+static void
+page_flip_handler(int fd, unsigned int frame,
+ unsigned int sec, unsigned int usec, void *data)
+{
+ (void) fd;
+ (void) frame;
+ (void) sec;
+ (void) usec;
+
+ int *waiting_for_flip = data;
+ *waiting_for_flip = 0;
+}
+
+static void
+sigint_handler(int sig, siginfo_t *si, void *__unused)
+{
+ (void) sig;
+ (void) si;
+ (void) __unused;
+ sig_recv = 1;
+}
+
+static int
+legacy_run(struct drm_resources *drm, const struct gbm *gbm, struct egl *egl)
+{
+ fd_set fds;
+ drmEventContext evctx = {
+ .version = 2,
+ .page_flip_handler = page_flip_handler,
+ };
+ struct gbm_bo *bo;
+ struct drm_fb *fb;
+ int ret;
+
+ struct sigaction sa;
+
+ sa.sa_flags = SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_sigaction = sigint_handler;
+ sigaction(SIGINT, &sa, NULL);
+
+
+ FD_ZERO(&fds);
+ FD_SET(0, &fds);
+ FD_SET(drm->drm_fd, &fds);
+
+ eglSwapBuffers(egl->display, egl->surface);
+ bo = gbm_surface_lock_front_buffer(gbm->surface);
+ if (!bo) {
+ return -1;
+ }
+
+ fb = drm_fb_get_from_bo(bo);
+ if (!fb) {
+ fprintf(stderr, "Failed to get a new framebuffer BO\n");
+ return -1;
+ }
+
+ fprintf(stdout, "Doing modeset on fd %d, CRCT_ID %d, CONNECTOR_ID %d\n",
+ drm->drm_fd, drm->crtc_id, drm->connector_id);
+
+ /* set mode: */
+ ret = drmModeSetCrtc(drm->drm_fd, drm->crtc_id, fb->fb_id, 0, 0,
+ &drm->connector_id, 1, drm->mode);
+ if (ret) {
+ printf("failed to set mode: %s\n", strerror(errno));
+ return ret;
+ }
+
+ while (1) {
+ struct gbm_bo *next_bo;
+ int waiting_for_flip = 1;
+
+ if (sig_recv) {
+ break;
+ }
+
+ egl->draw(egl);
+
+ eglSwapBuffers(egl->display, egl->surface);
+ next_bo = gbm_surface_lock_front_buffer(gbm->surface);
+ fb = drm_fb_get_from_bo(next_bo);
+ if (!fb) {
+ fprintf(stderr, "Failed to get a new framebuffer BO\n");
+ return -1;
+ }
+
+ /*
+ * Here you could also update drm plane layers if you want
+ * hw composition
+ */
+
+ ret = drmModePageFlip(drm->drm_fd, drm->crtc_id, fb->fb_id,
+ DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
+ if (ret) {
+ printf("failed to queue page flip: %s\n", strerror(errno));
+ return -1;
+ }
+
+ while (waiting_for_flip) {
+ ret = select(drm->drm_fd + 1, &fds, NULL, NULL, NULL);
+ if (ret < 0) {
+ printf("select err: %s\n", strerror(errno));
+ /* in case we get the signal in select() */
+ if (errno == EINTR) {
+ gbm_surface_release_buffer(gbm->surface, bo);
+ break;
+ }
+ return ret;
+ } else if (ret == 0) {
+ printf("select timeout!\n");
+ return -1;
+ } else if (FD_ISSET(0, &fds)) {
+ printf("user interrupted!\n");
+ break;
+ }
+ drmHandleEvent(drm->drm_fd, &evctx);
+ }
+
+ /* release last buffer to render on again: */
+ gbm_surface_release_buffer(gbm->surface, bo);
+ bo = next_bo;
+ }
+
+ return 0;
+}
+
+static void
+run(struct drm_resources *drm)
+{
+ struct gbm *gbm;
+ struct egl *egl;
+
+ drm->run = legacy_run;
+
+ gbm = init_gbm(drm->drm_fd, drm->mode->hdisplay, drm->mode->vdisplay);
+ if (!gbm) {
+ printf("failed to initialize GBM\n");
+ return;
+ }
+
+ fprintf(stdout, "gbm @ %p\n", gbm);
+
+ egl = init_triangle(gbm);
+ if (!egl) {
+ printf("failed to initialize EGL\n");
+ return;
+ }
+
+ drm->run(drm, gbm, egl);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct drm_resources drm_resources = {};
+ struct display *display;
+
+ /* FIXME: need to properly detect device */
+ const char *device = "/dev/dri/card0";
+
+ display = wl_create_display();
+ if (!display) {
+ exit(EXIT_FAILURE);
+ }
+
+ int drm_fd = open(device, O_RDWR);
+
+ /*
+ * this will populate the required info to perform modesetting and
+ * rendering hence the need to perform again initialization of drm
+ * is not necessary.
+ */
+ if (check_wl_drm_resources(display, drm_fd, &drm_resources) < 0) {
+ close(drm_fd);
+ wl_destroy_display(display);
+ fprintf(stdout, "Failed to get a proper lease\n");
+ exit(EXIT_FAILURE);
+ }
+ close(drm_fd);
+
+ run(&drm_resources);
+
+ zwp_kms_lease_request_v1_revoke(display->lease_request,
+ display->drm_display.lessee_id);
+
+ wl_display_dispatch(display->display);
+ wl_display_roundtrip(display->display);
+
+ wl_destroy_display(display);
+ return 0;
+}
diff --git a/clients/simple-egl-lease.h b/clients/simple-egl-lease.h
new file mode 100644
index 0000000..3036276
--- /dev/null
+++ b/clients/simple-egl-lease.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __SIMPLE_EGL_LEASE_H
+#define __SIMPLE_EGL_LEASE_H
+
+#ifndef EGL_KHR_platform_gbm
+#define EGL_KHR_platform_gbm 1
+#define EGL_PLATFORM_GBM_KHR 0x31D7
+#endif /* EGL_KHR_platform_gbm */
+
+#ifndef EGL_EXT_platform_base
+#define EGL_EXT_platform_base 1
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT (EGLenum platform, void *native_display, const EGLint *attrib_list);
+#endif
+#endif /* EGL_EXT_platform_base */
+
+struct gbm {
+ struct gbm_device *dev;
+ struct gbm_surface *surface;
+ int width, height;
+};
+
+struct egl {
+ EGLDisplay display;
+ EGLConfig config;
+ EGLContext context;
+ EGLSurface surface;
+
+ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
+ void (*draw)(struct egl *gl);
+};
+
+struct gl {
+ struct egl egl;
+ GLfloat aspect;
+ GLuint program;
+
+ GLuint rotation_uniform;
+ GLuint pos;
+ GLuint col;
+};
+
+struct drm_resources {
+ int drm_fd;
+
+ uint32_t connector_id;
+ uint32_t crtc_id;
+ uint32_t plane_id;
+
+ uint32_t crtc_index;
+ drmModeModeInfo *mode;
+
+ int (*run)(struct drm_resources *drm, const struct gbm *gbm, struct egl *egl);
+};
+
+struct drm_fb {
+ struct gbm_bo *bo;
+ uint32_t fb_id;
+};
+
+struct display {
+ struct wl_display *display;
+ struct wl_registry *registry;
+ struct wl_compositor *compositor;
+
+ struct zwp_kms_lease_manager_v1 *lease_manager;
+ struct zwp_kms_lease_request_v1 *lease_request;
+
+ struct {
+ int leased_fd;
+ uint32_t lessee_id;
+ } drm_display;
+};
+
+
+#endif
diff --git a/configure.ac b/configure.ac
index 97e3661..7afeb90 100644
--- a/configure.ac
+++ b/configure.ac
@@ -391,6 +391,23 @@ if test x$enable_simple_egl_clients = xyes; then
[egl glesv2 wayland-client wayland-egl wayland-cursor])
fi
+AC_ARG_ENABLE(simple-egl-lease-clients,
+ AS_HELP_STRING([--disable-simple-egl-lease-clients],
+ [do not build the simple EGL clients]),,
+ enable_simple_egl_lease_clients="$enable_egl")
+AM_CONDITIONAL(BUILD_SIMPLE_EGL_LEASE_CLIENTS, test "x$enable_simple_egl_lease_clients" = "xyes")
+if test x$enable_simple_egl_lease_clients = xyes; then
+ PKG_CHECK_MODULES(SIMPLE_EGL_LEASE_CLIENT,
+ [egl glesv2 wayland-client])
+
+ PKG_CHECK_MODULES(DRM_LEASE, [libdrm >= 2.4.89],
+ [AC_DEFINE([HAVE_DRM_LEASE], 1, [libdrm support lease capability])],
+ [AC_MSG_WARN([libdrm doesn't have leases support, will omit that capability])])
+ PKG_CHECK_MODULES(GBM, [gbm >= 10.2],
+ [AC_DEFINE([HAVE_GBM], 1, [gbm support])],
+ [AC_MSG_WARN([no gbm support])])
+fi
+
AC_ARG_ENABLE(simple-dmabuf-drm-client,
AS_HELP_STRING([--disable-simple-dmabuf-drm-client],
[do not build the simple dmabuf drm client]),,
--
2.9.3
More information about the wayland-devel
mailing list