static int drm_egl_init(struct MPGLContext *ctx, int flags) { struct priv *p = ctx->priv; p->kms = NULL; p->old_crtc = NULL; p->gbm.surface = NULL; p->gbm.device = NULL; p->active = false; p->waiting_for_flip = false; p->ev.version = DRM_EVENT_CONTEXT_VERSION; p->ev.page_flip_handler = page_flipped; p->vt_switcher_active = vt_switcher_init(&p->vt_switcher, ctx->vo->log); if (p->vt_switcher_active) { vt_switcher_acquire(&p->vt_switcher, acquire_vt, ctx); vt_switcher_release(&p->vt_switcher, release_vt, ctx); } else { MP_WARN(ctx->vo, "Failed to set up VT switcher. Terminal switching will be unavailable.\n"); } MP_VERBOSE(ctx->vo, "Initializing KMS\n"); p->kms = kms_create(ctx->vo->log); if (!p->kms) { MP_ERR(ctx->vo, "Failed to create KMS.\n"); return -1; } // TODO: arguments should be configurable if (!kms_setup(p->kms, "/dev/dri/card0", -1, 0)) { MP_ERR(ctx->vo, "Failed to configure KMS.\n"); return -1; } if (!init_gbm(ctx)) { MP_ERR(ctx->vo, "Failed to setup GBM.\n"); return -1; } if (!init_egl(ctx, flags & VOFLAG_GLES)) { MP_ERR(ctx->vo, "Failed to setup EGL.\n"); return -1; } if (!eglMakeCurrent(p->egl.display, p->egl.surface, p->egl.surface, p->egl.context)) { MP_ERR(ctx->vo, "Failed to make context current.\n"); return -1; } const char *egl_exts = eglQueryString(p->egl.display, EGL_EXTENSIONS); void *(*gpa)(const GLubyte*) = (void *(*)(const GLubyte*))eglGetProcAddress; mpgl_load_functions(ctx->gl, gpa, egl_exts, ctx->vo->log); // required by gbm_surface_lock_front_buffer eglSwapBuffers(p->egl.display, p->egl.surface); MP_VERBOSE(ctx->vo, "Preparing framebuffer\n"); p->gbm.bo = gbm_surface_lock_front_buffer(p->gbm.surface); if (!p->gbm.bo) { MP_ERR(ctx->vo, "Failed to lock GBM surface.\n"); return -1; } update_framebuffer_from_bo(ctx, p->gbm.bo); if (!p->fb.id) { MP_ERR(ctx->vo, "Failed to create framebuffer.\n"); return -1; } if (!crtc_setup(ctx)) { MP_ERR( ctx->vo, "Failed to set CRTC for connector %u: %s\n", p->kms->connector->connector_id, mp_strerror(errno)); return -1; } return 0; }
bool NativeStateDRM::init() { fd_ = open("/dev/dri/card0", O_RDWR); if (fd_ < 0) { Log::error("Failed to find a suitable DRM device\n"); return false; } resources_ = drmModeGetResources(fd_); if (!resources_) { Log::error("drmModeGetResources failed\n"); return false; } // Find a connected connector for (int c = 0; c < resources_->count_connectors; c++) { connector_ = drmModeGetConnector(fd_, resources_->connectors[c]); if (DRM_MODE_CONNECTED == connector_->connection) { break; } drmModeFreeConnector(connector_); connector_ = 0; } if (!connector_) { Log::error("Failed to find a suitable connector\n"); return false; } // Find the best resolution (we will always operate full-screen). unsigned int bestArea(0); for (int m = 0; m < connector_->count_modes; m++) { drmModeModeInfo* curMode = &connector_->modes[m]; unsigned int curArea = curMode->hdisplay * curMode->vdisplay; if (curArea > bestArea) { mode_ = curMode; bestArea = curArea; } } if (!mode_) { Log::error("Failed to find a suitable mode\n"); return false; } // Find a suitable encoder for (int e = 0; e < resources_->count_encoders; e++) { encoder_ = drmModeGetEncoder(fd_, resources_->encoders[e]); if (encoder_ && encoder_->encoder_id == connector_->encoder_id) { break; } drmModeFreeEncoder(encoder_); encoder_ = 0; } if (!encoder_) { Log::error("Failed to find a suitable encoder\n"); return false; } if (!init_gbm()) { return false; } crtc_ = drmModeGetCrtc(fd_, encoder_->crtc_id); if (!crtc_) { Log::error("Failed to get current CRTC\n"); return false; } signal(SIGINT, &NativeStateDRM::quit_handler); return true; }
int main(int argc, char *argv[]) { const char *device = "/dev/dri/card0"; const char *video = NULL; enum mode mode = SMOOTH; uint64_t modifier = DRM_FORMAT_MOD_LINEAR; unsigned int num_modifiers = 0; uint64_t *modifiers = NULL; int samples = 0; int atomic = 0; int opt; #ifdef HAVE_GST gst_init(&argc, &argv); GST_DEBUG_CATEGORY_INIT(kmscube_debug, "kmscube", 0, "kmscube video pipeline"); #endif while ((opt = getopt_long_only(argc, argv, shortopts, longopts, NULL)) != -1) { switch (opt) { case 'A': atomic = 1; break; case 'D': device = optarg; break; case 'M': if (strcmp(optarg, "smooth") == 0) { mode = SMOOTH; } else if (strcmp(optarg, "rgba") == 0) { mode = RGBA; } else if (strcmp(optarg, "nv12-2img") == 0) { mode = NV12_2IMG; } else if (strcmp(optarg, "nv12-1img") == 0) { mode = NV12_1IMG; } else { printf("invalid mode: %s\n", optarg); usage(argv[0]); return -1; } break; case 'm': modifier = strtoull(optarg, NULL, 0); modifiers = &modifier; num_modifiers = 1; break; case 's': samples = strtoul(optarg, NULL, 0); break; case 'V': mode = VIDEO; video = optarg; break; default: usage(argv[0]); return -1; } } if (atomic) drm = init_drm_atomic(device, modifiers, num_modifiers); else drm = init_drm_legacy(device); if (!drm) { printf("failed to initialize %s DRM\n", atomic ? "atomic" : "legacy"); return -1; } gbm = init_gbm(drm); if (!gbm) { printf("failed to initialize GBM\n"); return -1; } if (mode == SMOOTH) egl = init_cube_smooth(gbm, samples); else if (mode == VIDEO) egl = init_cube_video(gbm, video, samples); else egl = init_cube_tex(gbm, mode, samples); if (!egl) { printf("failed to initialize EGL\n"); return -1; } /* clear the color buffer */ glClearColor(0.5, 0.5, 0.5, 1.0); glClear(GL_COLOR_BUFFER_BIT); return drm->run(gbm, egl); }
static int drm_egl_init(struct MPGLContext *ctx, int flags) { if (ctx->vo->probing) { MP_VERBOSE(ctx->vo, "DRM EGL backend can be activated only manually.\n"); return -1; } struct priv *p = ctx->priv; p->kms = NULL; p->old_crtc = NULL; p->gbm.surface = NULL; p->gbm.device = NULL; p->active = false; p->waiting_for_flip = false; p->ev.version = DRM_EVENT_CONTEXT_VERSION; p->ev.page_flip_handler = page_flipped; p->vt_switcher_active = vt_switcher_init(&p->vt_switcher, ctx->vo->log); if (p->vt_switcher_active) { vt_switcher_acquire(&p->vt_switcher, acquire_vt, ctx); vt_switcher_release(&p->vt_switcher, release_vt, ctx); } else { MP_WARN(ctx->vo, "Failed to set up VT switcher. Terminal switching will be unavailable.\n"); } MP_VERBOSE(ctx->vo, "Initializing KMS\n"); p->kms = kms_create(ctx->vo->log, ctx->vo->opts->drm_connector_spec, ctx->vo->opts->drm_mode_id); if (!p->kms) { MP_ERR(ctx->vo, "Failed to create KMS.\n"); return -1; } if (!init_gbm(ctx)) { MP_ERR(ctx->vo, "Failed to setup GBM.\n"); return -1; } if (!init_egl(ctx, flags)) { MP_ERR(ctx->vo, "Failed to setup EGL.\n"); return -1; } if (!eglMakeCurrent(p->egl.display, p->egl.surface, p->egl.surface, p->egl.context)) { MP_ERR(ctx->vo, "Failed to make context current.\n"); return -1; } const char *egl_exts = eglQueryString(p->egl.display, EGL_EXTENSIONS); void *(*gpa)(const GLubyte*) = (void *(*)(const GLubyte*))eglGetProcAddress; mpgl_load_functions(ctx->gl, gpa, egl_exts, ctx->vo->log); ctx->native_display_type = "drm"; ctx->native_display = (void *)(intptr_t)p->kms->fd; // required by gbm_surface_lock_front_buffer eglSwapBuffers(p->egl.display, p->egl.surface); MP_VERBOSE(ctx->vo, "Preparing framebuffer\n"); p->gbm.bo = gbm_surface_lock_front_buffer(p->gbm.surface); if (!p->gbm.bo) { MP_ERR(ctx->vo, "Failed to lock GBM surface.\n"); return -1; } update_framebuffer_from_bo(ctx, p->gbm.bo); if (!p->fb.id) { MP_ERR(ctx->vo, "Failed to create framebuffer.\n"); return -1; } if (!crtc_setup(ctx)) { MP_ERR(ctx->vo, "Failed to set CRTC for connector %u: %s\n", p->kms->connector->connector_id, mp_strerror(errno)); return -1; } return 0; }
int init_egl_drm() { fd_set fds; drmEventContext evctx = { .version = DRM_EVENT_CONTEXT_VERSION, .vblank_handler = 0, .page_flip_handler = page_flip_handler, }; struct gbm_bo *bo; struct drm_fb *fb; ret = init_drm(); if (ret) { printf("failed to initialize DRM\n"); return ret; } printf("### Primary display => ConnectorId = %d, Resolution = %dx%d\n", drm.connector_id[DISP_ID], drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay); FD_ZERO(&fds); FD_SET(drm.fd, &fds); ret = init_gbm(); if (ret) { printf("failed to initialize GBM\n"); return ret; } //Initialise egl regularly here } void egl_drm_draw_flip() { /* set mode: */ if (all_display) { for (i=0; i<drm.ndisp; i++) { ret = drmModeSetCrtc(drm.fd, drm.crtc_id[i], fb->fb_id, 0, 0, &drm.connector_id[i], 1, drm.mode[i]); if (ret) { printf("display %d failed to set mode: %s\n", i, strerror(errno)); return ret; } } } else { ret = drmModeSetCrtc(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id, 0, 0, &drm.connector_id[DISP_ID], 1, drm.mode[DISP_ID]); if (ret) { printf("display %d failed to set mode: %s\n", DISP_ID, strerror(errno)); return ret; } } //Draw call here //Swapping is involved 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[DISP_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)) { continue; } drmHandleEvent(drm.fd, &evctx); } /* release last buffer to render on again: */ gbm_surface_release_buffer(gbm.surface, bo); bo = next_bo; }
int main(int argc, char *argv[]) { struct opt_data opts; optproc(argc, argv, &opts); if(audio_init(&opts) < 0) exit(1); if(opts.w < 0 && opts.h < 0) opts.w = opts.h = 512; else if(opts.w < 0) opts.w = opts.h; else if(opts.h < 0) opts.h = opts.w; int ret; ret = init_drm(&opts, 512); if (ret) { printf("failed to initialize DRM\n"); return ret; } ret = init_gbm(); if (ret) { printf("failed to initialize GBM\n"); return ret; } ret = init_egl(); if (ret) { printf("failed to initialize EGL\n"); return ret; } // call init_gl //init_gl(&opts, drm.mode->hdisplay, drm.mode->vdisplay); init_gl(&opts, opts.w, opts.h); //TODO: better dealing with our great big screen eglSwapBuffers(gl.display, gl.surface); struct gbm_bo *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; } // turn off line buffering on input and echoing of characters struct termios term; tcgetattr(STDIN_FILENO, &save_term); tcgetattr(STDIN_FILENO, &term); term.c_lflag &= ~(ICANON|ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &term); atexit(shutdown_cleanup); drmVBlank vbl; /* Get current count first hopefully also sync up with blank too*/ vbl.request.type = DRM_VBLANK_RELATIVE; vbl.request.sequence = 1; ret = drmWaitVBlank(drm.fd, &vbl); if (ret != 0) { printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret); return -1; } printf("starting msc: %d\n", vbl.request.sequence); /* Queue an event for frame + 1 */ vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; vbl.request.sequence = 1; vbl.request.signal = NULL; ret = drmWaitVBlank(drm.fd, &vbl); if (ret != 0) { printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret); return -1; } struct pollfd pfds[] = { {drm.fd, POLLIN | POLLPRI, 0 }, {STDIN_FILENO, POLLIN, 0 }, }; int debug_maxsrc = 0, debug_pal = 0, show_mandel = 0, show_fps_hist = 0; bool done = false; while (!done) { render_frame(debug_maxsrc, debug_pal, show_mandel, show_fps_hist); while (waiting_for_flip) { // TODO: input handling ret = poll(pfds, 2, -1); if (ret < 0) { printf("poll err: %s\n", strerror(errno)); return ret; } else if (ret == 0) { printf("poll timeout!\n"); done = true; break; } if (pfds[1].revents) { char buf[128]; int cnt = read(STDIN_FILENO, buf, sizeof(buf)); if(buf[0] == 27) done = true; else if(buf[0] == '1') debug_maxsrc = !debug_maxsrc; else if(buf[0] == '2') debug_pal = !debug_pal; else if(buf[0] == '3') show_mandel = !show_mandel; else if(buf[0] == '4') show_fps_hist = !show_fps_hist; //continue; } if(pfds[0].revents) drmHandleEvent(drm.fd, &evctx); } /* release last buffer to render on again: */ gbm_surface_release_buffer(gbm.surface, bo); bo = next_bo; } audio_shutdown(); return ret; }