filename | src/drivers/video_egl.c |
changeset | 1245:01e0020adf88 |
next | 1251:b8ab59d39756 |
author | nkeynes |
date | Fri Mar 02 23:49:10 2012 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Android WIP: * Rename gui_jni.c to gui_android.c - now quite android specific. * Implement generic EGL driver with very minimal Java wrapper * Run emulation in separate thread, and implement simple queue for inter-thread communication. * Add menu/action-bar items for start + reset |
file | annotate | diff | log | raw |
nkeynes@1245 | 1 | /** |
nkeynes@1245 | 2 | * $Id$ |
nkeynes@1245 | 3 | * |
nkeynes@1245 | 4 | * Window management using EGL. |
nkeynes@1245 | 5 | * |
nkeynes@1245 | 6 | * Copyright (c) 2012 Nathan Keynes. |
nkeynes@1245 | 7 | * |
nkeynes@1245 | 8 | * This program is free software; you can redistribute it and/or modify |
nkeynes@1245 | 9 | * it under the terms of the GNU General Public License as published by |
nkeynes@1245 | 10 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@1245 | 11 | * (at your option) any later version. |
nkeynes@1245 | 12 | * |
nkeynes@1245 | 13 | * This program is distributed in the hope that it will be useful, |
nkeynes@1245 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@1245 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@1245 | 16 | * GNU General Public License for more details. |
nkeynes@1245 | 17 | */ |
nkeynes@1245 | 18 | |
nkeynes@1245 | 19 | #include "lxdream.h" |
nkeynes@1245 | 20 | #include "display.h" |
nkeynes@1245 | 21 | #include "video_egl.h" |
nkeynes@1245 | 22 | #include "video_gl.h" |
nkeynes@1245 | 23 | #include "pvr2/pvr2.h" |
nkeynes@1245 | 24 | #include "pvr2/glutil.h" |
nkeynes@1245 | 25 | |
nkeynes@1245 | 26 | static const char *getEGLErrorString( EGLint code ) |
nkeynes@1245 | 27 | { |
nkeynes@1245 | 28 | switch( code ) { |
nkeynes@1245 | 29 | case EGL_SUCCESS: return "OK"; |
nkeynes@1245 | 30 | case EGL_NOT_INITIALIZED: return "EGL not initialized"; |
nkeynes@1245 | 31 | case EGL_BAD_ACCESS: return "Bad access"; |
nkeynes@1245 | 32 | case EGL_BAD_ALLOC: return "Allocation failed"; |
nkeynes@1245 | 33 | case EGL_BAD_ATTRIBUTE: return "Bad attribute"; |
nkeynes@1245 | 34 | case EGL_BAD_CONTEXT: return "Bad context"; |
nkeynes@1245 | 35 | case EGL_BAD_CONFIG: return "Bad config"; |
nkeynes@1245 | 36 | case EGL_BAD_CURRENT_SURFACE: return "Bad current surface"; |
nkeynes@1245 | 37 | case EGL_BAD_DISPLAY: return "Bad display"; |
nkeynes@1245 | 38 | case EGL_BAD_MATCH: return "Bad match"; |
nkeynes@1245 | 39 | case EGL_BAD_PARAMETER: return "Bad parameter"; |
nkeynes@1245 | 40 | case EGL_BAD_NATIVE_PIXMAP: return "Bad native pixmap"; |
nkeynes@1245 | 41 | case EGL_BAD_NATIVE_WINDOW: return "Bad native window"; |
nkeynes@1245 | 42 | default: return "Unknown error"; |
nkeynes@1245 | 43 | } |
nkeynes@1245 | 44 | } |
nkeynes@1245 | 45 | |
nkeynes@1245 | 46 | |
nkeynes@1245 | 47 | static void logEGLError(const char *msg) |
nkeynes@1245 | 48 | { |
nkeynes@1245 | 49 | EGLint error = eglGetError(); |
nkeynes@1245 | 50 | const char *errorStr = getEGLErrorString(error); |
nkeynes@1245 | 51 | |
nkeynes@1245 | 52 | ERROR( "%s: %s (%x)", msg, errorStr, error ); |
nkeynes@1245 | 53 | } |
nkeynes@1245 | 54 | |
nkeynes@1245 | 55 | static const EGLint RGB888_attributes[] = { |
nkeynes@1245 | 56 | EGL_RED_SIZE, 8, |
nkeynes@1245 | 57 | EGL_GREEN_SIZE, 8, |
nkeynes@1245 | 58 | EGL_BLUE_SIZE, 8, |
nkeynes@1245 | 59 | EGL_DEPTH_SIZE, 16, |
nkeynes@1245 | 60 | EGL_STENCIL_SIZE, 8, |
nkeynes@1245 | 61 | EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
nkeynes@1245 | 62 | EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT, |
nkeynes@1245 | 63 | EGL_NONE, EGL_NONE }; |
nkeynes@1245 | 64 | |
nkeynes@1245 | 65 | static const EGLint RGB565_attributes[] = { |
nkeynes@1245 | 66 | EGL_RED_SIZE, 5, |
nkeynes@1245 | 67 | EGL_GREEN_SIZE, 6, |
nkeynes@1245 | 68 | EGL_BLUE_SIZE, 5, |
nkeynes@1245 | 69 | EGL_DEPTH_SIZE, 16, |
nkeynes@1245 | 70 | EGL_STENCIL_SIZE, 8, |
nkeynes@1245 | 71 | EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
nkeynes@1245 | 72 | EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT, |
nkeynes@1245 | 73 | EGL_NONE, EGL_NONE }; |
nkeynes@1245 | 74 | |
nkeynes@1245 | 75 | static const EGLint context_attributes[] = { |
nkeynes@1245 | 76 | EGL_CONTEXT_CLIENT_VERSION, 2, |
nkeynes@1245 | 77 | EGL_NONE, EGL_NONE }; |
nkeynes@1245 | 78 | |
nkeynes@1245 | 79 | static EGLDisplay display; |
nkeynes@1245 | 80 | static EGLContext context = EGL_NO_CONTEXT; |
nkeynes@1245 | 81 | static EGLSurface surface = EGL_NO_SURFACE; |
nkeynes@1245 | 82 | static gboolean fbo_created = FALSE; |
nkeynes@1245 | 83 | |
nkeynes@1245 | 84 | gboolean video_egl_set_window(EGLNativeWindowType window, int width, int height, int format) |
nkeynes@1245 | 85 | { |
nkeynes@1245 | 86 | EGLConfig config; |
nkeynes@1245 | 87 | EGLint num_config, major = 0, minor = 0; |
nkeynes@1245 | 88 | const EGLint *attribute_list; |
nkeynes@1245 | 89 | |
nkeynes@1245 | 90 | display = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
nkeynes@1245 | 91 | if( eglInitialize(display, &major, &minor) != EGL_TRUE ) { |
nkeynes@1245 | 92 | logEGLError( "Unable to initialise EGL display" ); |
nkeynes@1245 | 93 | return FALSE; |
nkeynes@1245 | 94 | } |
nkeynes@1245 | 95 | |
nkeynes@1245 | 96 | if( format == COLFMT_RGB565 || format == COLFMT_BGRA1555 ) { |
nkeynes@1245 | 97 | attribute_list = RGB565_attributes; |
nkeynes@1245 | 98 | } else { |
nkeynes@1245 | 99 | attribute_list = RGB888_attributes; |
nkeynes@1245 | 100 | } |
nkeynes@1245 | 101 | |
nkeynes@1245 | 102 | |
nkeynes@1245 | 103 | eglChooseConfig(display, attribute_list, &config, 1, &num_config); |
nkeynes@1245 | 104 | |
nkeynes@1245 | 105 | context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes); |
nkeynes@1245 | 106 | if( context == EGL_NO_CONTEXT ) { |
nkeynes@1245 | 107 | logEGLError( "Unable to create EGL context" ); |
nkeynes@1245 | 108 | video_egl_clear_window(); |
nkeynes@1245 | 109 | return FALSE; |
nkeynes@1245 | 110 | } |
nkeynes@1245 | 111 | |
nkeynes@1245 | 112 | surface = eglCreateWindowSurface(display, config, window, NULL); |
nkeynes@1245 | 113 | if( surface == EGL_NO_SURFACE ) { |
nkeynes@1245 | 114 | logEGLError( "Unable to create EGL surface" ); |
nkeynes@1245 | 115 | video_egl_clear_window(); |
nkeynes@1245 | 116 | return FALSE; |
nkeynes@1245 | 117 | } |
nkeynes@1245 | 118 | |
nkeynes@1245 | 119 | if( eglMakeCurrent( display, surface, surface, context ) == EGL_FALSE ) { |
nkeynes@1245 | 120 | video_egl_clear_window(); |
nkeynes@1245 | 121 | return FALSE; |
nkeynes@1245 | 122 | } |
nkeynes@1245 | 123 | |
nkeynes@1245 | 124 | if( gl_fbo_is_supported() ) { |
nkeynes@1245 | 125 | display_gl_driver.capabilities.has_gl = TRUE; |
nkeynes@1245 | 126 | gl_fbo_init(&display_egl_driver); |
nkeynes@1245 | 127 | gl_vbo_init(&display_egl_driver); |
nkeynes@1245 | 128 | fbo_created = TRUE; |
nkeynes@1245 | 129 | } else { |
nkeynes@1245 | 130 | ERROR( "Display does not support FBO" ); |
nkeynes@1245 | 131 | video_egl_clear_window(); |
nkeynes@1245 | 132 | return FALSE; |
nkeynes@1245 | 133 | } |
nkeynes@1245 | 134 | pvr2_setup_gl_context(); |
nkeynes@1245 | 135 | INFO( "Initialised EGL %d.%d\n", major, minor ); |
nkeynes@1245 | 136 | return TRUE; |
nkeynes@1245 | 137 | } |
nkeynes@1245 | 138 | |
nkeynes@1245 | 139 | void video_egl_clear_window() |
nkeynes@1245 | 140 | { |
nkeynes@1245 | 141 | if( fbo_created ) { |
nkeynes@1245 | 142 | gl_fbo_shutdown(); |
nkeynes@1245 | 143 | fbo_created = FALSE; |
nkeynes@1245 | 144 | } |
nkeynes@1245 | 145 | eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
nkeynes@1245 | 146 | if( surface != EGL_NO_SURFACE ) { |
nkeynes@1245 | 147 | eglDestroySurface(display, surface); |
nkeynes@1245 | 148 | surface = EGL_NO_SURFACE; |
nkeynes@1245 | 149 | } |
nkeynes@1245 | 150 | if( context != EGL_NO_CONTEXT ) { |
nkeynes@1245 | 151 | eglDestroyContext(display, context); |
nkeynes@1245 | 152 | context = EGL_NO_CONTEXT; |
nkeynes@1245 | 153 | } |
nkeynes@1245 | 154 | eglTerminate(display); |
nkeynes@1245 | 155 | } |
nkeynes@1245 | 156 | |
nkeynes@1245 | 157 | |
nkeynes@1245 | 158 | |
nkeynes@1245 | 159 | /** |
nkeynes@1245 | 160 | * Minimal init and shutdown. The real work is done from set_window |
nkeynes@1245 | 161 | */ |
nkeynes@1245 | 162 | struct display_driver display_egl_driver = { |
nkeynes@1245 | 163 | "egl", N_("OpenGLES driver"), NULL, NULL, |
nkeynes@1245 | 164 | NULL, NULL, NULL, |
nkeynes@1245 | 165 | NULL, NULL, NULL, NULL, |
nkeynes@1245 | 166 | gl_load_frame_buffer, gl_display_render_buffer, gl_display_blank, |
nkeynes@1245 | 167 | NULL, gl_read_render_buffer, NULL, NULL |
nkeynes@1245 | 168 | }; |
.