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 | 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 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel