/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author: Daniel van Vugt */ #include "eglapp.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include #include #include static const char appname[] = "egldemo"; static MirConnection *connection; static MirSurface *surface; static EGLDisplay egldisplay; static EGLSurface eglsurface; static volatile sig_atomic_t running = 0; #define CHECK(_cond, _err) \ if (!(_cond)) \ { \ printf("%s\n", (_err)); \ return 0; \ } void mir_eglapp_shutdown(void) { eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglTerminate(egldisplay); mir_surface_release_sync(surface); surface = NULL; mir_connection_release(connection); connection = NULL; } static void shutdown(int signum) { if (running) { running = 0; printf("Signal %d received. Good night.\n", signum); } } mir_eglapp_bool mir_eglapp_running(void) { return running; } void mir_eglapp_swap_buffers(void) { static time_t lasttime = 0; static int lastcount = 0; static int count = 0; time_t now = time(NULL); time_t dtime; int dcount; if (!running) return; eglSwapBuffers(egldisplay, eglsurface); count++; dcount = count - lastcount; dtime = now - lasttime; if (dtime) { printf("%d FPS\n", dcount); lasttime = now; lastcount = count; } } static void mir_eglapp_handle_input(MirSurface* surface, MirEvent const* ev, void* context) { (void) surface; (void) context; if (ev->type == mir_event_type_key && ev->key.key_code == XKB_KEY_q && ev->key.action == mir_key_action_up) { running = 0; } } static unsigned int get_bpp(MirPixelFormat pf) { switch (pf) { case mir_pixel_format_abgr_8888: case mir_pixel_format_xbgr_8888: case mir_pixel_format_argb_8888: case mir_pixel_format_xrgb_8888: return 32; case mir_pixel_format_bgr_888: return 24; case mir_pixel_format_invalid: default: return 0; } } static const MirDisplayOutput *find_active_output( const MirDisplayConfiguration *conf) { const MirDisplayOutput *output = NULL; int d; for (d = 0; d < (int)conf->num_outputs; d++) { const MirDisplayOutput *out = conf->outputs + d; if (out->used && out->connected && out->num_modes && out->current_mode < out->num_modes) { output = out; break; } } return output; } mir_eglapp_bool mir_eglapp_init(int argc, char *argv[], unsigned int *width, unsigned int *height) { EGLint ctxattribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; MirSurfaceParameters surfaceparm = { "eglappsurface", 256, 256, mir_pixel_format_xbgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; MirEventDelegate delegate = { mir_eglapp_handle_input, NULL }; EGLConfig eglconfig; EGLint neglconfigs; EGLContext eglctx; EGLBoolean ok; EGLint swapinterval = 1; char *mir_socket = NULL; if (argc > 1) { int i; for (i = 1; i < argc; i++) { mir_eglapp_bool help = 0; const char *arg = argv[i]; if (arg[0] == '-') { switch (arg[1]) { case 'n': swapinterval = 0; break; case 'o': { unsigned int output_id = 0; arg += 2; if (!arg[0] && i < argc-1) { i++; arg = argv[i]; } if (sscanf(arg, "%u", &output_id) == 1) { surfaceparm.output_id = output_id; } else { printf("Invalid output ID: %s\n", arg); help = 1; } } break; case 'f': *width = 0; *height = 0; break; case 's': { unsigned int w, h; arg += 2; if (!arg[0] && i < argc-1) { i++; arg = argv[i]; } if (sscanf(arg, "%ux%u", &w, &h) == 2) { *width = w; *height = h; } else { printf("Invalid size: %s\n", arg); help = 1; } } break; case 'm': mir_socket = argv[++i]; break; case 'h': default: help = 1; break; } } else { help = 1; } if (help) { printf("Usage: %s []\n" " -h Show this help text\n" " -f Force full screen\n" " -o ID Force placement on output monitor ID\n" " -n Don't sync to vblank\n" " -m socket Mir server socket\n" " -s WIDTHxHEIGHT Force surface size\n" , argv[0]); return 0; } } } connection = mir_connect_sync(mir_socket, appname); CHECK(mir_connection_is_valid(connection), "Can't get connection"); /* eglapps are interested in the screen size, so use mir_connection_create_display_config */ MirDisplayConfiguration* display_config = mir_connection_create_display_config(connection); const MirDisplayOutput *output = find_active_output(display_config); if (output == NULL) { printf("No active outputs found.\n"); return 0; } const MirDisplayMode *mode = &output->modes[output->current_mode]; unsigned int valid_formats; mir_connection_get_available_surface_formats(connection, &surfaceparm.pixel_format, 1, &valid_formats); printf("Connected to display: resolution (%dx%d), position(%dx%d), " "supports %d pixel formats\n", mode->horizontal_resolution, mode->vertical_resolution, output->position_x, output->position_y, output->num_output_formats); surfaceparm.width = *width > 0 ? *width : mode->horizontal_resolution; surfaceparm.height = *height > 0 ? *height : mode->vertical_resolution; mir_display_config_destroy(display_config); printf("Using pixel format #%d\n", surfaceparm.pixel_format); unsigned int bpp = get_bpp(surfaceparm.pixel_format); EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, EGL_BUFFER_SIZE, bpp, EGL_NONE }; surface = mir_connection_create_surface_sync(connection, &surfaceparm); CHECK(mir_surface_is_valid(surface), "Can't create a surface"); mir_surface_set_event_handler(surface, &delegate); egldisplay = eglGetDisplay( mir_connection_get_egl_native_display(connection)); CHECK(egldisplay != EGL_NO_DISPLAY, "Can't eglGetDisplay"); ok = eglInitialize(egldisplay, NULL, NULL); CHECK(ok, "Can't eglInitialize"); ok = eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs); CHECK(ok, "Could not eglChooseConfig"); CHECK(neglconfigs > 0, "No EGL config available"); eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, (EGLNativeWindowType)mir_surface_get_egl_native_window(surface), NULL); CHECK(eglsurface != EGL_NO_SURFACE, "eglCreateWindowSurface failed"); eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, ctxattribs); CHECK(eglctx != EGL_NO_CONTEXT, "eglCreateContext failed"); ok = eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx); CHECK(ok, "Can't eglMakeCurrent"); signal(SIGINT, shutdown); signal(SIGTERM, shutdown); *width = surfaceparm.width; *height = surfaceparm.height; eglSwapInterval(egldisplay, swapinterval); running = 1; return 1; } struct MirConnection* mir_eglapp_native_connection() { return connection; } struct MirSurface* mir_eglapp_native_surface() { return surface; }