Heavily inspired by kmscube and simple-egl. Uses legacy page-flipping and
triangle shaders from simple-egl.

Signed-off-by: Marius Vlad <marius-cristian.v...@nxp.com>
---
 Makefile.am                |  11 +
 clients/simple-egl-lease.c | 880 +++++++++++++++++++++++++++++++++++++++++++++
 clients/simple-egl-lease.h |  99 +++++
 configure.ac               |  17 +
 4 files changed, 1007 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 4580d24..8177313 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -656,6 +656,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..7425120
--- /dev/null
+++ b/clients/simple-egl-lease.c
@@ -0,0 +1,880 @@
+/*
+ * 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, &registry_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_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->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_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 e1aa0cd..80059b9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -388,6 +388,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

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to