/* * Copyright (c) 2017 Rob Clark * * 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 #include #include #include #include "common.h" #include "drm-common.h" static struct drm drm; static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { /* suppress 'unused parameter' warnings */ (void)fd, (void)frame, (void)sec, (void)usec; 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 = 2, .page_flip_handler = page_flip_handler, }; struct gbm_bo *bo; struct drm_fb *fb; uint32_t i = 0; int64_t start_time, report_time, cur_time; int ret; if (gbm->surface) { eglSwapBuffers(egl->display, egl->surface); bo = gbm_surface_lock_front_buffer(gbm->surface); } else { bo = gbm->bos[0]; } fb = drm_fb_get_from_bo(bo); if (!fb) { fprintf(stderr, "Failed to get a new framebuffer BO\n"); return -1; } /* 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; } start_time = report_time = get_time_ns(); while (i < drm.count) { unsigned frame = i; struct gbm_bo *next_bo; int waiting_for_flip = 1; /* Start fps measuring on second frame, to remove the time spent * compiling shader, etc, from the fps: */ if (i == 1) { start_time = report_time = get_time_ns(); } if (!gbm->surface) { glBindFramebuffer(GL_FRAMEBUFFER, egl->fbs[frame % NUM_BUFFERS].fb); } egl->draw(i++); if (gbm->surface) { eglSwapBuffers(egl->display, egl->surface); next_bo = gbm_surface_lock_front_buffer(gbm->surface); } else { glFinish(); next_bo = gbm->bos[frame % NUM_BUFFERS]; } 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.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) { FD_ZERO(&fds); FD_SET(0, &fds); FD_SET(drm.fd, &fds); 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"); return 0; } drmHandleEvent(drm.fd, &evctx); } cur_time = get_time_ns(); if (cur_time > (report_time + 2 * NSEC_PER_SEC)) { double elapsed_time = cur_time - start_time; double secs = elapsed_time / (double)NSEC_PER_SEC; unsigned frames = i - 1; /* first frame ignored */ printf("Rendered %u frames in %f sec (%f fps)\n", frames, secs, (double)frames/secs); report_time = cur_time; } /* release last buffer to render on again: */ if (gbm->surface) { gbm_surface_release_buffer(gbm->surface, bo); } bo = next_bo; } finish_perfcntrs(); cur_time = get_time_ns(); double elapsed_time = cur_time - start_time; double secs = elapsed_time / (double)NSEC_PER_SEC; unsigned frames = i - 1; /* first frame ignored */ printf("Rendered %u frames in %f sec (%f fps)\n", frames, secs, (double)frames/secs); dump_perfcntrs(frames, elapsed_time); return 0; } const struct drm * init_drm_legacy(const char *device, const char *mode_str, unsigned int vrefresh, unsigned int count) { int ret; ret = init_drm(&drm, device, mode_str, vrefresh, count); if (ret) return NULL; drm.run = legacy_run; return &drm; }