diff options
author | Rob Clark <robdclark@gmail.com> | 2017-02-21 17:01:16 -0500 |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2017-02-22 10:31:02 -0500 |
commit | 1f1158fe1279e845420d3cb838eff3bbf2e5701a (patch) | |
tree | 95fe331b322f1a4d67ed1f1c77b36c0cb8ece71c | |
parent | 3e78eabeeeeb8476583cf2d37f1bd561307694db (diff) |
split out legacy (pageflip) kms
Preping to add new atomic alternative path.
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | common.c | 3 | ||||
-rw-r--r-- | common.h | 6 | ||||
-rw-r--r-- | drm-legacy.c | 124 | ||||
-rw-r--r-- | drm.c | 202 | ||||
-rw-r--r-- | drm.h | 49 | ||||
-rw-r--r-- | kmscube.c | 271 |
7 files changed, 387 insertions, 271 deletions
diff --git a/Makefile.am b/Makefile.am index ae17157..24cc49c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,6 +44,9 @@ kmscube_SOURCES = \ common.h \ cube-smooth.c \ cube-tex.c \ + drm.c \ + drm.h \ + drm-legacy.c \ frame-512x512-NV12.c \ frame-512x512-RGBA.c \ kmscube.c \ @@ -21,8 +21,11 @@ * DEALINGS IN THE SOFTWARE. */ +#include <errno.h> +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "common.h" @@ -33,12 +33,6 @@ #include <gbm.h> #include <drm/drm_fourcc.h> -#define GL_GLEXT_PROTOTYPES 1 -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <EGL/egl.h> -#include <EGL/eglext.h> - struct gbm { struct gbm_device *dev; struct gbm_surface *surface; diff --git a/drm-legacy.c b/drm-legacy.c new file mode 100644 index 0000000..29d5f3c --- /dev/null +++ b/drm-legacy.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2017 Rob Clark <rclark@redhat.com> + * + * 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, sub license, + * 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 NON-INFRINGEMENT. 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. + */ + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#include "common.h" +#include "drm.h" + +static struct drm drm; + +static void page_flip_handler(int fd, unsigned int frame, + unsigned int sec, unsigned int usec, void *data) +{ + int *waiting_for_flip = data; + *waiting_for_flip = 0; +} + +static int legacy_run(const struct gbm *gbm, const struct egl *egl) +{ + fd_set fds; + drmEventContext evctx = { + .version = DRM_EVENT_CONTEXT_VERSION, + .page_flip_handler = page_flip_handler, + }; + struct gbm_bo *bo; + struct drm_fb *fb; + uint32_t i = 0; + int ret; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(drm.fd, &fds); + + eglSwapBuffers(egl->display, egl->surface); + bo = gbm_surface_lock_front_buffer(gbm->surface); + fb = drm_fb_get_from_bo(bo); + + /* set mode: */ + ret = drmModeSetCrtc(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; + + egl->draw(i++); + + eglSwapBuffers(egl->display, egl->surface); + next_bo = gbm_surface_lock_front_buffer(gbm->surface); + fb = drm_fb_get_from_bo(next_bo); + + /* + * Here you could also update drm plane layers if you want + * hw composition + */ + + ret = drmModePageFlip(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.fd + 1, &fds, NULL, NULL, NULL); + if (ret < 0) { + printf("select err: %s\n", strerror(errno)); + 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.fd, &evctx); + } + + /* release last buffer to render on again: */ + gbm_surface_release_buffer(gbm->surface, bo); + bo = next_bo; + } + + return 0; +} + +const struct drm * init_drm_legacy(const char *device) +{ + int ret; + + ret = init_drm(&drm, device); + if (ret) + return NULL; + + drm.run = legacy_run; + + return &drm; +} @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2017 Rob Clark <rclark@redhat.com> + * + * 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, sub license, + * 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 NON-INFRINGEMENT. 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. + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "common.h" +#include "drm.h" + +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; + struct gbm_device *gbm = gbm_bo_get_device(bo); + + if (fb->fb_id) + drmModeRmFB(drm_fd, fb->fb_id); + + free(fb); +} + +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, stride, handle; + int ret; + + if (fb) + return fb; + + fb = calloc(1, sizeof *fb); + fb->bo = bo; + + width = gbm_bo_get_width(bo); + height = gbm_bo_get_height(bo); + stride = gbm_bo_get_stride(bo); + handle = gbm_bo_get_handle(bo).u32; + + ret = drmModeAddFB(drm_fd, width, height, 24, 32, stride, handle, &fb->fb_id); + 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 uint32_t find_crtc_for_encoder(const drmModeRes *resources, + const drmModeEncoder *encoder) { + int i; + + for (i = 0; i < resources->count_crtcs; i++) { + /* possible_crtcs is a bitmask as described here: + * https://dvdhrm.wordpress.com/2012/09/13/linux-drm-mode-setting-api + */ + const uint32_t crtc_mask = 1 << i; + const uint32_t crtc_id = resources->crtcs[i]; + if (encoder->possible_crtcs & crtc_mask) { + return crtc_id; + } + } + + /* no match found */ + return -1; +} + +static uint32_t find_crtc_for_connector(const struct drm *drm, const drmModeRes *resources, + const drmModeConnector *connector) { + int i; + + for (i = 0; i < connector->count_encoders; i++) { + const uint32_t encoder_id = connector->encoders[i]; + drmModeEncoder *encoder = drmModeGetEncoder(drm->fd, encoder_id); + + if (encoder) { + const uint32_t crtc_id = find_crtc_for_encoder(resources, encoder); + + drmModeFreeEncoder(encoder); + if (crtc_id != 0) { + return crtc_id; + } + } + } + + /* no match found */ + return -1; +} + +int init_drm(struct drm *drm, const char *device) +{ + drmModeRes *resources; + drmModeConnector *connector = NULL; + drmModeEncoder *encoder = NULL; + int i, area; + + drm->fd = open(device, O_RDWR); + + if (drm->fd < 0) { + printf("could not open drm device\n"); + return -1; + } + + resources = drmModeGetResources(drm->fd); + if (!resources) { + printf("drmModeGetResources failed: %s\n", strerror(errno)); + return -1; + } + + /* find a connected connector: */ + for (i = 0; i < resources->count_connectors; i++) { + connector = drmModeGetConnector(drm->fd, resources->connectors[i]); + if (connector->connection == DRM_MODE_CONNECTED) { + /* it's connected, let's use this! */ + break; + } + drmModeFreeConnector(connector); + connector = NULL; + } + + if (!connector) { + /* we could be fancy and listen for hotplug events and wait for + * a connector.. + */ + printf("no connected connector!\n"); + return -1; + } + + /* find prefered mode or the highest resolution mode: */ + 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->mode = current_mode; + } + + int current_area = current_mode->hdisplay * current_mode->vdisplay; + if (current_area > area) { + drm->mode = current_mode; + area = current_area; + } + } + + if (!drm->mode) { + printf("could not find mode!\n"); + return -1; + } + + /* find encoder: */ + for (i = 0; i < resources->count_encoders; i++) { + encoder = drmModeGetEncoder(drm->fd, resources->encoders[i]); + if (encoder->encoder_id == connector->encoder_id) + break; + drmModeFreeEncoder(encoder); + encoder = NULL; + } + + if (encoder) { + drm->crtc_id = encoder->crtc_id; + } else { + uint32_t crtc_id = find_crtc_for_connector(drm, resources, connector); + if (crtc_id == 0) { + printf("no crtc found!\n"); + return -1; + } + + drm->crtc_id = crtc_id; + } + + drmModeFreeResources(resources); + + drm->connector_id = connector->connector_id; + + return 0; +} @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017 Rob Clark <rclark@redhat.com> + * + * 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, sub license, + * 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 NON-INFRINGEMENT. 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 _DRM_H +#define _DRM_H + +#include <xf86drm.h> +#include <xf86drmMode.h> + +struct drm { + int fd; + drmModeModeInfo *mode; + uint32_t crtc_id; + uint32_t connector_id; + + int (*run)(const struct gbm *gbm, const struct egl *egl); +}; + +struct drm_fb { + struct gbm_bo *bo; + uint32_t fb_id; +}; + +struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo); + +int init_drm(struct drm *drm, const char *device); +const struct drm * init_drm_legacy(const char *device); + +#endif /* _DRM_H */ @@ -24,213 +24,19 @@ /* Based on a egl cube test app originally written by Arvin Schnell */ -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> #include <string.h> #include <stdio.h> -#include <stdlib.h> #include <getopt.h> -#include <errno.h> - -#include <xf86drm.h> -#include <xf86drmMode.h> - -#include <assert.h> #include "common.h" +#include "drm.h" #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) static const struct egl *egl; static const struct gbm *gbm; - -static struct { - int fd; - drmModeModeInfo *mode; - uint32_t crtc_id; - uint32_t connector_id; -} drm; - -struct drm_fb { - struct gbm_bo *bo; - uint32_t fb_id; -}; - -static uint32_t find_crtc_for_encoder(const drmModeRes *resources, - const drmModeEncoder *encoder) { - int i; - - for (i = 0; i < resources->count_crtcs; i++) { - /* possible_crtcs is a bitmask as described here: - * https://dvdhrm.wordpress.com/2012/09/13/linux-drm-mode-setting-api - */ - const uint32_t crtc_mask = 1 << i; - const uint32_t crtc_id = resources->crtcs[i]; - if (encoder->possible_crtcs & crtc_mask) { - return crtc_id; - } - } - - /* no match found */ - return -1; -} - -static uint32_t find_crtc_for_connector(const drmModeRes *resources, - const drmModeConnector *connector) { - int i; - - for (i = 0; i < connector->count_encoders; i++) { - const uint32_t encoder_id = connector->encoders[i]; - drmModeEncoder *encoder = drmModeGetEncoder(drm.fd, encoder_id); - - if (encoder) { - const uint32_t crtc_id = find_crtc_for_encoder(resources, encoder); - - drmModeFreeEncoder(encoder); - if (crtc_id != 0) { - return crtc_id; - } - } - } - - /* no match found */ - return -1; -} - -static int init_drm(const char *dev) -{ - drmModeRes *resources; - drmModeConnector *connector = NULL; - drmModeEncoder *encoder = NULL; - int i, area; - - drm.fd = open(dev, O_RDWR); - - if (drm.fd < 0) { - printf("could not open drm device\n"); - return -1; - } - - resources = drmModeGetResources(drm.fd); - if (!resources) { - printf("drmModeGetResources failed: %s\n", strerror(errno)); - return -1; - } - - /* find a connected connector: */ - for (i = 0; i < resources->count_connectors; i++) { - connector = drmModeGetConnector(drm.fd, resources->connectors[i]); - if (connector->connection == DRM_MODE_CONNECTED) { - /* it's connected, let's use this! */ - break; - } - drmModeFreeConnector(connector); - connector = NULL; - } - - if (!connector) { - /* we could be fancy and listen for hotplug events and wait for - * a connector.. - */ - printf("no connected connector!\n"); - return -1; - } - - /* find prefered mode or the highest resolution mode: */ - 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.mode = current_mode; - } - - int current_area = current_mode->hdisplay * current_mode->vdisplay; - if (current_area > area) { - drm.mode = current_mode; - area = current_area; - } - } - - if (!drm.mode) { - printf("could not find mode!\n"); - return -1; - } - - /* find encoder: */ - for (i = 0; i < resources->count_encoders; i++) { - encoder = drmModeGetEncoder(drm.fd, resources->encoders[i]); - if (encoder->encoder_id == connector->encoder_id) - break; - drmModeFreeEncoder(encoder); - encoder = NULL; - } - - if (encoder) { - drm.crtc_id = encoder->crtc_id; - } else { - uint32_t crtc_id = find_crtc_for_connector(resources, connector); - if (crtc_id == 0) { - printf("no crtc found!\n"); - return -1; - } - - drm.crtc_id = crtc_id; - } - - drm.connector_id = connector->connector_id; - - return 0; -} - -static void -drm_fb_destroy_callback(struct gbm_bo *bo, void *data) -{ - struct drm_fb *fb = data; - struct gbm_device *gbm = gbm_bo_get_device(bo); - - 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) -{ - struct drm_fb *fb = gbm_bo_get_user_data(bo); - uint32_t width, height, stride, handle; - int ret; - - if (fb) - return fb; - - fb = calloc(1, sizeof *fb); - fb->bo = bo; - - width = gbm_bo_get_width(bo); - height = gbm_bo_get_height(bo); - stride = gbm_bo_get_stride(bo); - handle = gbm_bo_get_handle(bo).u32; - - ret = drmModeAddFB(drm.fd, width, height, 24, 32, stride, handle, &fb->fb_id); - 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 page_flip_handler(int fd, unsigned int frame, - unsigned int sec, unsigned int usec, void *data) -{ - int *waiting_for_flip = data; - *waiting_for_flip = 0; -} +static const struct drm *drm; static const char *shortopts = "D:M:"; @@ -256,14 +62,6 @@ static void usage(const char *name) int main(int argc, char *argv[]) { - fd_set fds; - drmEventContext evctx = { - .version = DRM_EVENT_CONTEXT_VERSION, - .page_flip_handler = page_flip_handler, - }; - struct gbm_bo *bo; - struct drm_fb *fb; - uint32_t i = 0; const char *device = "/dev/dri/card0"; enum mode mode = SMOOTH; int opt, ret; @@ -294,17 +92,13 @@ int main(int argc, char *argv[]) } } - ret = init_drm(device); - if (ret) { + drm = init_drm_legacy(device); + if (!drm) { printf("failed to initialize DRM\n"); return ret; } - FD_ZERO(&fds); - FD_SET(0, &fds); - FD_SET(drm.fd, &fds); - - gbm = init_gbm(drm.fd, drm.mode->hdisplay, drm.mode->vdisplay); + gbm = init_gbm(drm->fd, drm->mode->hdisplay, drm->mode->vdisplay); if (!gbm) { printf("failed to initialize GBM\n"); return -1; @@ -324,59 +118,6 @@ int main(int argc, char *argv[]) /* clear the color buffer */ glClearColor(0.5, 0.5, 0.5, 1.0); glClear(GL_COLOR_BUFFER_BIT); - eglSwapBuffers(egl->display, egl->surface); - bo = gbm_surface_lock_front_buffer(gbm->surface); - fb = drm_fb_get_from_bo(bo); - - /* set mode: */ - ret = drmModeSetCrtc(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; - - egl->draw(i++); - - eglSwapBuffers(egl->display, egl->surface); - next_bo = gbm_surface_lock_front_buffer(gbm->surface); - fb = drm_fb_get_from_bo(next_bo); - - /* - * Here you could also update drm plane layers if you want - * hw composition - */ - - ret = drmModePageFlip(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.fd + 1, &fds, NULL, NULL, NULL); - if (ret < 0) { - printf("select err: %s\n", strerror(errno)); - 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.fd, &evctx); - } - - /* release last buffer to render on again: */ - gbm_surface_release_buffer(gbm->surface, bo); - bo = next_bo; - } - return ret; + return drm->run(gbm, egl); } |