nkeynes@1245: /** nkeynes@1245: * $Id$ nkeynes@1245: * nkeynes@1245: * Window management using EGL. nkeynes@1245: * nkeynes@1245: * Copyright (c) 2012 Nathan Keynes. nkeynes@1245: * nkeynes@1245: * This program is free software; you can redistribute it and/or modify nkeynes@1245: * it under the terms of the GNU General Public License as published by nkeynes@1245: * the Free Software Foundation; either version 2 of the License, or nkeynes@1245: * (at your option) any later version. nkeynes@1245: * nkeynes@1245: * This program is distributed in the hope that it will be useful, nkeynes@1245: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@1245: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@1245: * GNU General Public License for more details. nkeynes@1245: */ nkeynes@1245: nkeynes@1245: #include "lxdream.h" nkeynes@1245: #include "display.h" nkeynes@1245: #include "video_egl.h" nkeynes@1245: #include "video_gl.h" nkeynes@1245: #include "pvr2/pvr2.h" nkeynes@1245: #include "pvr2/glutil.h" nkeynes@1245: nkeynes@1245: static const char *getEGLErrorString( EGLint code ) nkeynes@1245: { nkeynes@1245: switch( code ) { nkeynes@1245: case EGL_SUCCESS: return "OK"; nkeynes@1245: case EGL_NOT_INITIALIZED: return "EGL not initialized"; nkeynes@1245: case EGL_BAD_ACCESS: return "Bad access"; nkeynes@1245: case EGL_BAD_ALLOC: return "Allocation failed"; nkeynes@1245: case EGL_BAD_ATTRIBUTE: return "Bad attribute"; nkeynes@1245: case EGL_BAD_CONTEXT: return "Bad context"; nkeynes@1245: case EGL_BAD_CONFIG: return "Bad config"; nkeynes@1245: case EGL_BAD_CURRENT_SURFACE: return "Bad current surface"; nkeynes@1245: case EGL_BAD_DISPLAY: return "Bad display"; nkeynes@1245: case EGL_BAD_MATCH: return "Bad match"; nkeynes@1245: case EGL_BAD_PARAMETER: return "Bad parameter"; nkeynes@1245: case EGL_BAD_NATIVE_PIXMAP: return "Bad native pixmap"; nkeynes@1245: case EGL_BAD_NATIVE_WINDOW: return "Bad native window"; nkeynes@1245: default: return "Unknown error"; nkeynes@1245: } nkeynes@1245: } nkeynes@1245: nkeynes@1245: nkeynes@1245: static void logEGLError(const char *msg) nkeynes@1245: { nkeynes@1245: EGLint error = eglGetError(); nkeynes@1245: const char *errorStr = getEGLErrorString(error); nkeynes@1245: nkeynes@1245: ERROR( "%s: %s (%x)", msg, errorStr, error ); nkeynes@1245: } nkeynes@1245: nkeynes@1245: static const EGLint RGB888_attributes[] = { nkeynes@1245: EGL_RED_SIZE, 8, nkeynes@1245: EGL_GREEN_SIZE, 8, nkeynes@1245: EGL_BLUE_SIZE, 8, nkeynes@1245: EGL_DEPTH_SIZE, 16, nkeynes@1245: EGL_STENCIL_SIZE, 8, nkeynes@1245: EGL_SURFACE_TYPE, EGL_WINDOW_BIT, nkeynes@1245: EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT, nkeynes@1245: EGL_NONE, EGL_NONE }; nkeynes@1245: nkeynes@1245: static const EGLint RGB565_attributes[] = { nkeynes@1245: EGL_RED_SIZE, 5, nkeynes@1245: EGL_GREEN_SIZE, 6, nkeynes@1245: EGL_BLUE_SIZE, 5, nkeynes@1245: EGL_DEPTH_SIZE, 16, nkeynes@1245: EGL_STENCIL_SIZE, 8, nkeynes@1245: EGL_SURFACE_TYPE, EGL_WINDOW_BIT, nkeynes@1245: EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT, nkeynes@1245: EGL_NONE, EGL_NONE }; nkeynes@1245: nkeynes@1245: static const EGLint context_attributes[] = { nkeynes@1245: EGL_CONTEXT_CLIENT_VERSION, 2, nkeynes@1245: EGL_NONE, EGL_NONE }; nkeynes@1245: nkeynes@1245: static EGLDisplay display; nkeynes@1245: static EGLContext context = EGL_NO_CONTEXT; nkeynes@1245: static EGLSurface surface = EGL_NO_SURFACE; nkeynes@1245: static gboolean fbo_created = FALSE; nkeynes@1245: nkeynes@1245: gboolean video_egl_set_window(EGLNativeWindowType window, int width, int height, int format) nkeynes@1245: { nkeynes@1245: EGLConfig config; nkeynes@1245: EGLint num_config, major = 0, minor = 0; nkeynes@1245: const EGLint *attribute_list; nkeynes@1245: nkeynes@1245: display = eglGetDisplay(EGL_DEFAULT_DISPLAY); nkeynes@1245: if( eglInitialize(display, &major, &minor) != EGL_TRUE ) { nkeynes@1245: logEGLError( "Unable to initialise EGL display" ); nkeynes@1245: return FALSE; nkeynes@1245: } nkeynes@1245: nkeynes@1245: if( format == COLFMT_RGB565 || format == COLFMT_BGRA1555 ) { nkeynes@1245: attribute_list = RGB565_attributes; nkeynes@1245: } else { nkeynes@1245: attribute_list = RGB888_attributes; nkeynes@1245: } nkeynes@1245: nkeynes@1245: nkeynes@1245: eglChooseConfig(display, attribute_list, &config, 1, &num_config); nkeynes@1245: nkeynes@1245: context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes); nkeynes@1245: if( context == EGL_NO_CONTEXT ) { nkeynes@1245: logEGLError( "Unable to create EGL context" ); nkeynes@1245: video_egl_clear_window(); nkeynes@1245: return FALSE; nkeynes@1245: } nkeynes@1245: nkeynes@1245: surface = eglCreateWindowSurface(display, config, window, NULL); nkeynes@1245: if( surface == EGL_NO_SURFACE ) { nkeynes@1245: logEGLError( "Unable to create EGL surface" ); nkeynes@1245: video_egl_clear_window(); nkeynes@1245: return FALSE; nkeynes@1245: } nkeynes@1245: nkeynes@1245: if( eglMakeCurrent( display, surface, surface, context ) == EGL_FALSE ) { nkeynes@1245: video_egl_clear_window(); nkeynes@1245: return FALSE; nkeynes@1245: } nkeynes@1245: nkeynes@1245: if( gl_fbo_is_supported() ) { nkeynes@1251: display_egl_driver.capabilities.has_gl = TRUE; nkeynes@1251: display_egl_driver.capabilities.depth_bits = 16; /* TODO: get from config info */ nkeynes@1245: gl_fbo_init(&display_egl_driver); nkeynes@1245: gl_vbo_init(&display_egl_driver); nkeynes@1256: glsl_init(&display_egl_driver); nkeynes@1245: fbo_created = TRUE; nkeynes@1245: } else { nkeynes@1245: ERROR( "Display does not support FBO" ); nkeynes@1245: video_egl_clear_window(); nkeynes@1245: return FALSE; nkeynes@1245: } nkeynes@1251: gl_set_video_size(width, height, 0); nkeynes@1245: pvr2_setup_gl_context(); nkeynes@1245: INFO( "Initialised EGL %d.%d\n", major, minor ); nkeynes@1245: return TRUE; nkeynes@1245: } nkeynes@1245: nkeynes@1245: void video_egl_clear_window() nkeynes@1245: { nkeynes@1245: if( fbo_created ) { nkeynes@1245: gl_fbo_shutdown(); nkeynes@1245: fbo_created = FALSE; nkeynes@1245: } nkeynes@1245: eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); nkeynes@1245: if( surface != EGL_NO_SURFACE ) { nkeynes@1245: eglDestroySurface(display, surface); nkeynes@1245: surface = EGL_NO_SURFACE; nkeynes@1245: } nkeynes@1245: if( context != EGL_NO_CONTEXT ) { nkeynes@1245: eglDestroyContext(display, context); nkeynes@1245: context = EGL_NO_CONTEXT; nkeynes@1245: } nkeynes@1245: eglTerminate(display); nkeynes@1245: } nkeynes@1245: nkeynes@1251: static void video_egl_swap_buffers() nkeynes@1251: { nkeynes@1251: eglSwapBuffers(display, surface); nkeynes@1251: } nkeynes@1245: nkeynes@1245: nkeynes@1245: /** nkeynes@1245: * Minimal init and shutdown. The real work is done from set_window nkeynes@1245: */ nkeynes@1245: struct display_driver display_egl_driver = { nkeynes@1245: "egl", N_("OpenGLES driver"), NULL, NULL, nkeynes@1245: NULL, NULL, NULL, nkeynes@1245: NULL, NULL, NULL, NULL, nkeynes@1245: gl_load_frame_buffer, gl_display_render_buffer, gl_display_blank, nkeynes@1251: video_egl_swap_buffers, gl_read_render_buffer, NULL, NULL nkeynes@1245: };