Search
lxdream.org :: lxdream/src/drivers/video_egl.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/video_egl.c
changeset 1287:dac8f363f1fe
prev1275:83b15705cdde
author nkeynes
date Sat Jan 26 14:00:48 2013 +1000 (11 years ago)
permissions -rw-r--r--
last change Change glib includes to #include <glib.h> rather than the individual
headers, as recent glib versions are breaking on this
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@1287
    75
static const EGLint alt_attributes[] = {
nkeynes@1287
    76
        EGL_DEPTH_SIZE,     16,
nkeynes@1287
    77
        EGL_STENCIL_SIZE,   8,
nkeynes@1287
    78
        EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,
nkeynes@1287
    79
        EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT,
nkeynes@1287
    80
        EGL_NONE, EGL_NONE };
nkeynes@1287
    81
nkeynes@1245
    82
static const EGLint context_attributes[] = {
nkeynes@1245
    83
        EGL_CONTEXT_CLIENT_VERSION, 2,
nkeynes@1245
    84
        EGL_NONE, EGL_NONE };
nkeynes@1245
    85
nkeynes@1275
    86
static EGLDisplay display = EGL_NO_DISPLAY;
nkeynes@1245
    87
static EGLContext context = EGL_NO_CONTEXT;
nkeynes@1245
    88
static EGLSurface surface = EGL_NO_SURFACE;
nkeynes@1245
    89
static gboolean fbo_created = FALSE;
nkeynes@1245
    90
nkeynes@1287
    91
static void video_egl_swap_buffers();
nkeynes@1287
    92
static int video_egl_major = 0, video_egl_minor = 0;
nkeynes@1287
    93
nkeynes@1287
    94
gboolean video_egl_init()
nkeynes@1245
    95
{
nkeynes@1245
    96
    display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
nkeynes@1287
    97
    if( eglInitialize(display, &video_egl_major, &video_egl_minor) != EGL_TRUE ) {
nkeynes@1245
    98
        logEGLError( "Unable to initialise EGL display" );
nkeynes@1245
    99
        return FALSE;
nkeynes@1245
   100
    }
nkeynes@1287
   101
    return TRUE;
nkeynes@1287
   102
}
nkeynes@1287
   103
nkeynes@1287
   104
gboolean video_egl_init_context( EGLNativeWindowType window, int format )
nkeynes@1287
   105
{
nkeynes@1287
   106
    EGLConfig config;
nkeynes@1287
   107
    EGLint num_config;
nkeynes@1287
   108
    const EGLint *attribute_list;
nkeynes@1245
   109
nkeynes@1245
   110
    if( format == COLFMT_RGB565 || format == COLFMT_BGRA1555 ) {
nkeynes@1245
   111
        attribute_list = RGB565_attributes;
nkeynes@1245
   112
    } else {
nkeynes@1245
   113
        attribute_list = RGB888_attributes;
nkeynes@1245
   114
    }
nkeynes@1287
   115
    eglChooseConfig(display, attribute_list, &config, 1, &num_config);
nkeynes@1245
   116
nkeynes@1287
   117
    surface = eglCreateWindowSurface(display, config, window, NULL);
nkeynes@1287
   118
    if( surface == EGL_NO_SURFACE ) {
nkeynes@1287
   119
        /* Try alternate config in case of failure. This provides a workaround for
nkeynes@1287
   120
         * the Nokia N900 where eglCreateWindowSurface fails when color attributes
nkeynes@1287
   121
         * are specified. (bug report: https://bugs.maemo.org/show_bug.cgi?id=9335)
nkeynes@1287
   122
         */
nkeynes@1287
   123
        eglChooseConfig(display, alt_attributes, &config, 1, &num_config);
nkeynes@1287
   124
        surface = eglCreateWindowSurface(display, config, window, NULL);
nkeynes@1245
   125
nkeynes@1287
   126
        if( surface == EGL_NO_SURFACE ) {
nkeynes@1287
   127
            logEGLError( "Unable to create EGL surface" );
nkeynes@1287
   128
            video_egl_shutdown();
nkeynes@1287
   129
            return FALSE;
nkeynes@1287
   130
        }
nkeynes@1287
   131
    }
nkeynes@1245
   132
nkeynes@1245
   133
    context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes);
nkeynes@1245
   134
    if( context == EGL_NO_CONTEXT ) {
nkeynes@1245
   135
        logEGLError( "Unable to create EGL context" );
nkeynes@1287
   136
        video_egl_shutdown();
nkeynes@1245
   137
        return FALSE;
nkeynes@1245
   138
    }
nkeynes@1245
   139
nkeynes@1287
   140
nkeynes@1287
   141
nkeynes@1287
   142
    if( eglMakeCurrent( display, surface, surface, context ) == EGL_FALSE ) {
nkeynes@1287
   143
        logEGLError( "Unable to make EGL context current" );
nkeynes@1287
   144
        video_egl_shutdown();
nkeynes@1245
   145
        return FALSE;
nkeynes@1245
   146
    }
nkeynes@1245
   147
nkeynes@1287
   148
    return TRUE;
nkeynes@1287
   149
}
nkeynes@1245
   150
nkeynes@1287
   151
gboolean video_egl_init_driver( display_driver_t driver )
nkeynes@1287
   152
{
nkeynes@1287
   153
    driver->swap_buffers = video_egl_swap_buffers;
nkeynes@1287
   154
    driver->capabilities.depth_bits = 16; /* TODO: get from config info */
nkeynes@1287
   155
    if( !gl_init_driver(driver, TRUE) ) {
nkeynes@1287
   156
        video_egl_shutdown();
nkeynes@1245
   157
        return FALSE;
nkeynes@1245
   158
    }
nkeynes@1258
   159
    fbo_created = TRUE;
nkeynes@1245
   160
    return TRUE;
nkeynes@1245
   161
}
nkeynes@1245
   162
nkeynes@1287
   163
void video_egl_shutdown()
nkeynes@1245
   164
{
nkeynes@1245
   165
    if( fbo_created ) {
nkeynes@1275
   166
        pvr2_shutdown_gl_context();
nkeynes@1245
   167
        gl_fbo_shutdown();
nkeynes@1245
   168
        fbo_created = FALSE;
nkeynes@1245
   169
    }
nkeynes@1245
   170
    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
nkeynes@1245
   171
    if( surface != EGL_NO_SURFACE )  {
nkeynes@1245
   172
        eglDestroySurface(display, surface);
nkeynes@1245
   173
        surface = EGL_NO_SURFACE;
nkeynes@1245
   174
    }
nkeynes@1245
   175
    if( context != EGL_NO_CONTEXT ) {
nkeynes@1245
   176
        eglDestroyContext(display, context);
nkeynes@1245
   177
        context = EGL_NO_CONTEXT;
nkeynes@1245
   178
    }
nkeynes@1275
   179
    if( display != EGL_NO_DISPLAY ) {
nkeynes@1275
   180
        eglTerminate(display);
nkeynes@1275
   181
        display = EGL_NO_DISPLAY;
nkeynes@1275
   182
    }
nkeynes@1287
   183
}
nkeynes@1287
   184
nkeynes@1287
   185
gboolean video_egl_set_window(EGLNativeWindowType window, int width, int height, int format)
nkeynes@1287
   186
{
nkeynes@1287
   187
    if( ! video_egl_init() ||
nkeynes@1287
   188
            ! video_egl_init_context( window, format ) ||
nkeynes@1287
   189
            ! video_egl_init_driver( &display_egl_driver ) ) {
nkeynes@1287
   190
        return FALSE;
nkeynes@1287
   191
    }
nkeynes@1287
   192
    gl_set_video_size(width, height, 0);
nkeynes@1287
   193
    pvr2_setup_gl_context();
nkeynes@1287
   194
    INFO( "Initialised EGL %d.%d", video_egl_major, video_egl_minor );
nkeynes@1287
   195
    return TRUE;
nkeynes@1287
   196
}
nkeynes@1287
   197
nkeynes@1287
   198
void video_egl_clear_window()
nkeynes@1287
   199
{
nkeynes@1287
   200
    video_egl_shutdown();
nkeynes@1275
   201
    INFO( "Terminated EGL" );
nkeynes@1245
   202
}
nkeynes@1245
   203
nkeynes@1251
   204
static void video_egl_swap_buffers()
nkeynes@1251
   205
{
nkeynes@1251
   206
    eglSwapBuffers(display, surface);
nkeynes@1251
   207
}
nkeynes@1245
   208
nkeynes@1245
   209
nkeynes@1245
   210
/**
nkeynes@1245
   211
 * Minimal init and shutdown. The real work is done from set_window
nkeynes@1245
   212
 */
nkeynes@1245
   213
struct display_driver display_egl_driver = {
nkeynes@1245
   214
        "egl", N_("OpenGLES driver"), NULL, NULL,
nkeynes@1245
   215
        NULL, NULL, NULL,
nkeynes@1245
   216
        NULL, NULL, NULL, NULL,
nkeynes@1245
   217
        gl_load_frame_buffer, gl_display_render_buffer, gl_display_blank,
nkeynes@1251
   218
        video_egl_swap_buffers, gl_read_render_buffer, NULL, NULL
nkeynes@1245
   219
};
.