view src/video/qnxgf/SDL_qnxgf.c @ 3168:6338b7f2d024

Hi, I have prepared a set of patches to readd WindowsCE support to SDL 1.3. I've created a new GAPI/Rawframebuffer and a DirectDraw renderer. Both renderers are work in progress and there are several unimplemented cases. (Notably RenderLine/RenderPoint/RenderFill/QueryTexturePixels/UpdateTexture and texture blending ) Nevertheless I am successfully using these renderers together with the SDL software renderer. (On most devices the SDL software renderer will be much faster as there are only badly optimized vendor drivers available) I send these patches now in this unpolished state because there seems to be some interest in win ce and someone has to start supporting SDL 1.3 Now on to the patches: wince_events_window_fixes.patch fixes some wince incompatibilities and adds fullscreen support via SHFullScreen. NOTE: This patch shouldn't have any side effects on Windows, but I have NOT tested it on Windows, so please double-check. This patch doesn't dependent on the following ones. wince_renderers_system.patch This patch does all necessary modifications to the SDL system. - it adds the renderers to the configure system - it adds the renderers to win32video SDL_ceddrawrender.c SDL_ceddrawrender.h SDL_gapirender_c.h SDL_gapirender.c SDL_gapirender.h these files add the new render drivers and should be placed in src/video/win32 Some notes to people who want to test this: - I have only compiled sdl with ming32ce, so the VisualC files are not up to date - As mingw32ce has no ddraw.h this file must be taken from the MS SDK and modified to work with gcc - I had to modify line 2611 in configure.in to EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lcoredll -lcommctrl -lmmtimer -Wl,--image-base -Wl,0x10000" otherwise GetCPinfo wouldn't link. If someone knows whats causing this I'd be happy to hear about it. It would be great if these patches could make their way into SVN as this would make collaboration much much easier. I'm out of office for the next week and therefore will be unavailable via email. Regards Stefan
author Sam Lantinga <slouken@libsdl.org>
date Sun, 07 Jun 2009 02:44:46 +0000
parents 7f684f249ec9
children 44d5474c2c8a
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2009 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Sam Lantinga
    slouken@libsdl.org

    QNX Graphics Framework SDL driver
    Copyright (C) 2009 Mike Gorchak
    (mike@malva.ua, lestat@i.com.ua)
*/

#include "SDL_config.h"

#include "../SDL_sysvideo.h"
#include "SDL_version.h"
#include "SDL_syswm.h"
#include "SDL_loadso.h"

/* Include QNX Graphics Framework declarations */
#include <gf/gf.h>

#include "SDL_qnxgf.h"
#include "SDL_gf_render.h"
#include "SDL_gf_pixelfmt.h"
#include "SDL_gf_opengles.h"
#include "SDL_gf_input.h"

/******************************************************************************/
/* SDL Generic video modes, which could provide GF                            */
/* This is real pain in the ass. GF is just wrapper around a selected driver  */
/* some drivers could support double scan modes, like 320x200, 512x384, etc   */
/* but some drivers are not. Later we can distinguish one driver from another */
/* Feel free to add any new custom graphics mode                              */
/******************************************************************************/
static SDL_DisplayMode generic_mode[] = {
    {0, 320, 200, 70, NULL},    /* 320x200 modes are 70Hz and 85Hz          */
    {0, 320, 200, 85, NULL},
    {0, 320, 240, 70, NULL},    /* 320x240 modes are 70Hz and 85Hz          */
    {0, 320, 240, 85, NULL},
    {0, 400, 300, 60, NULL},    /* 400x300 mode is 60Hz only                */
    {0, 480, 360, 60, NULL},    /* 480x360 mode is 60Hz only                */
    {0, 512, 384, 60, NULL},    /* 512x384 modes are 60Hz and 70Hz          */
    {0, 512, 384, 70, NULL},
    {0, 640, 480, 60, NULL},    /* 640x480 modes are 60Hz, 75Hz, 85Hz       */
    {0, 640, 480, 75, NULL},
    {0, 640, 480, 85, NULL},
    {0, 800, 600, 60, NULL},    /* 800x600 modes are 60Hz, 75Hz, 85Hz       */
    {0, 800, 600, 75, NULL},
    {0, 800, 600, 85, NULL},
    {0, 800, 480, 60, NULL},    /* 800x480 mode is 60Hz only                */
    {0, 848, 480, 60, NULL},    /* 848x480 mode is 60Hz only                */
    {0, 960, 600, 60, NULL},    /* 960x600 mode is 60Hz only                */
    {0, 1024, 640, 60, NULL},   /* 1024x640 mode is 60Hz only               */
    {0, 1024, 768, 60, NULL},   /* 1024x768 modes are 60Hz, 70Hz, 75Hz      */
    {0, 1024, 768, 70, NULL},
    {0, 1024, 768, 75, NULL},
    {0, 1088, 612, 60, NULL},   /* 1088x612 mode is 60Hz only               */
    {0, 1152, 864, 60, NULL},   /* 1152x864 modes are 60Hz, 70Hz, 72Hz      */
    {0, 1152, 864, 70, NULL},   /* 75Hz and 85Hz                            */
    {0, 1152, 864, 72, NULL},
    {0, 1152, 864, 75, NULL},
    {0, 1152, 864, 85, NULL},
    {0, 1280, 720, 60, NULL},   /* 1280x720 mode is 60Hz only               */
    {0, 1280, 768, 60, NULL},   /* 1280x768 mode is 60Hz only               */
    {0, 1280, 800, 60, NULL},   /* 1280x800 mode is 60Hz only               */
    {0, 1280, 960, 60, NULL},   /* 1280x960 mode is 60Hz only               */
    {0, 1280, 1024, 60, NULL},  /* 1280x1024 modes are 60Hz, 75Hz, 85Hz and */
    {0, 1280, 1024, 75, NULL},  /* 100 Hz                                   */
    {0, 1280, 1024, 85, NULL},  /*                                          */
    {0, 1280, 1024, 100, NULL}, /*                                          */
    {0, 1360, 768, 60, NULL},   /* 1360x768 mode is 60Hz only               */
    {0, 1400, 1050, 60, NULL},  /* 1400x1050 mode is 60Hz only              */
    {0, 1440, 900, 60, NULL},   /* 1440x900 mode is 60Hz only               */
    {0, 1440, 960, 60, NULL},   /* 1440x960 mode is 60Hz only               */
    {0, 1600, 900, 60, NULL},   /* 1600x900 mode is 60Hz only               */
    {0, 1600, 1024, 60, NULL},  /* 1600x1024 mode is 60Hz only              */
    {0, 1600, 1200, 60, NULL},  /* 1600x1200 mode is 60Hz only              */
    {0, 1680, 1050, 60, NULL},  /* 1680x1050 mode is 60Hz only              */
    {0, 1920, 1080, 60, NULL},  /* 1920x1080 mode is 60Hz only              */
    {0, 1920, 1200, 60, NULL},  /* 1920x1200 mode is 60Hz only              */
    {0, 1920, 1440, 60, NULL},  /* 1920x1440 mode is 60Hz only              */
    {0, 2048, 1536, 60, NULL},  /* 2048x1536 mode is 60Hz only              */
    {0, 2048, 1080, 60, NULL},  /* 2048x1080 mode is 60Hz only              */
    {0, 0, 0, 0, NULL}          /* End of generic mode list                 */
};

/* Low level device graphics driver names, which they are reporting */
GF_DeviceCaps gf_devicename[] = {
    /* ATI Rage 128 graphics driver (devg-ati_rage128)      */
    {"ati_rage128", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Fujitsu Carmine graphics driver (devg-carmine.so)    */
    {"carmine", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_ACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* C&T graphics driver (devg-chips.so)                  */
    {"chips", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Fujitsu Coral graphics driver (devg-coral.so)        */
    {"coral", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_ACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Intel integrated graphics driver (devg-extreme2.so)  */
    {"extreme2", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_ACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Unaccelerated FB driver (devg-flat.so)               */
    {"flat", SDL_GF_UNACCELERATED | SDL_GF_LOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_NOVIDEOMEMORY},
    /* NS Geode graphics driver (devg-geode.so)             */
    {"geode", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Geode LX graphics driver (devg-geodelx.so)           */
    {"geodelx", SDL_GF_ACCELERATED | SDL_GF_LOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Intel integrated graphics driver (devg-gma9xx.so)    */
    {"gma", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_ACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Intel integrated graphics driver (devg-i810.so)      */
    {"i810", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Intel integrated graphics driver (devg-i830.so)      */
    {"i830", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Geode LX graphics driver (devg-lx800.so)             */
    {"lx800", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Matrox Gxx graphics driver (devg-matroxg.so)         */
    {"matroxg", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Intel Poulsbo graphics driver (devg-poulsbo.so)      */
    {"poulsbo", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_ACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* ATI Radeon driver (devg-radeon.so)                   */
    {"radeon", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* ATI Rage driver (devg-rage.so)                       */
    {"rage", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* S3 Savage graphics driver (devg-s3_savage.so)        */
    {"s3_savage", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* SiS630 integrated graphics driver (devg-sis630.so)   */
    {"sis630", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* PowerVR SGX 535 graphics driver (devg-poulsbo.so)    */
    {"sgx", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_ACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* SM Voyager GX graphics driver (devg-smi5xx.so)       */
    {"smi5xx", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* Silicon Motion graphics driver (devg-smi7xx.so)      */
    {"smi7xx", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* SVGA unaccelerated gfx driver (devg-svga.so)         */
    {"svga", SDL_GF_UNACCELERATED | SDL_GF_LOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_NOVIDEOMEMORY},
    /* nVidia TNT graphics driver (devg-tnt.so)             */
    {"tnt", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* VIA integrated graphics driver (devg-tvia.so)        */
    {"tvia", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* VIA UniChrome graphics driver (devg-unichrome.so)    */
    {"unichrome", SDL_GF_ACCELERATED | SDL_GF_NOLOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* VESA unaccelerated gfx driver (devg-vesa.so)         */
    {"vesa", SDL_GF_UNACCELERATED | SDL_GF_LOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_NOVIDEOMEMORY},
    /* VmWare graphics driver (devg-volari.so)              */
    {"vmware", SDL_GF_ACCELERATED | SDL_GF_LOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_NOVIDEOMEMORY},
    /* XGI XP10 graphics driver (devg-volari.so)            */
    {"volari", SDL_GF_ACCELERATED | SDL_GF_LOWRESOLUTION |
     SDL_GF_UNACCELERATED_3D | SDL_GF_VIDEOMEMORY},
    /* End of list */
    {NULL, 0x00000000}
};

/*****************************************************************************/
/* SDL Video Device initialization functions                                 */
/*****************************************************************************/

static int
qnxgf_available(void)
{
    gf_dev_t gfdev;
    gf_dev_info_t gfdev_info;
    int status;

    /* Try to attach to graphics device driver */
    status = gf_dev_attach(&gfdev, GF_DEVICE_INDEX(0), &gfdev_info);
    if (status != GF_ERR_OK) {
        return 0;
    }

    /* Detach from graphics device driver for now */
    gf_dev_detach(gfdev);

    return 1;
}

static void
qnxgf_destroy(SDL_VideoDevice * device)
{
    SDL_VideoData *gfdata = (SDL_VideoData *) device->driverdata;

    /* Detach from graphics device driver, if it was initialized */
    if (gfdata->gfinitialized != SDL_FALSE) {
        gf_dev_detach(gfdata->gfdev);
        gfdata->gfdev = NULL;
    }

    if (device->driverdata != NULL) {
        device->driverdata = NULL;
    }
}

static SDL_VideoDevice *
qnxgf_create(int devindex)
{
    SDL_VideoDevice *device;
    SDL_VideoData *gfdata;
    int status;

    /* Initialize SDL_VideoDevice structure */
    device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
    if (device == NULL) {
        SDL_OutOfMemory();
        return NULL;
    }

    /* Initialize internal GF specific data */
    gfdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
    if (gfdata == NULL) {
        SDL_OutOfMemory();
        SDL_free(device);
        return NULL;
    }
    device->driverdata = gfdata;

    /* Try to attach to graphics device driver */
    status =
        gf_dev_attach(&gfdata->gfdev, GF_DEVICE_INDEX(devindex),
                      &gfdata->gfdev_info);
    if (status != GF_ERR_OK) {
        SDL_OutOfMemory();
        SDL_free(gfdata);
        SDL_free(device);
        return NULL;
    }

    if (gfdata->gfdev_info.description == NULL) {
        gf_dev_detach(gfdata->gfdev);
        SDL_SetError("GF: Failed to initialize graphics driver");
        return NULL;
    }

    /* Setup amount of available displays and current display */
    device->num_displays = 0;
    device->current_display = 0;

    /* Setup device shutdown function */
    gfdata->gfinitialized = SDL_TRUE;
    device->free = qnxgf_destroy;

    /* Setup all functions which we can handle */
    device->VideoInit = qnxgf_videoinit;
    device->VideoQuit = qnxgf_videoquit;
    device->GetDisplayModes = qnxgf_getdisplaymodes;
    device->SetDisplayMode = qnxgf_setdisplaymode;
    device->SetDisplayPalette = qnxgf_setdisplaypalette;
    device->GetDisplayPalette = qnxgf_getdisplaypalette;
    device->SetDisplayGammaRamp = qnxgf_setdisplaygammaramp;
    device->GetDisplayGammaRamp = qnxgf_getdisplaygammaramp;
    device->CreateWindow = qnxgf_createwindow;
    device->CreateWindowFrom = qnxgf_createwindowfrom;
    device->SetWindowTitle = qnxgf_setwindowtitle;
    device->SetWindowIcon = qnxgf_setwindowicon;
    device->SetWindowPosition = qnxgf_setwindowposition;
    device->SetWindowSize = qnxgf_setwindowsize;
    device->ShowWindow = qnxgf_showwindow;
    device->HideWindow = qnxgf_hidewindow;
    device->RaiseWindow = qnxgf_raisewindow;
    device->MaximizeWindow = qnxgf_maximizewindow;
    device->MinimizeWindow = qnxgf_minimizewindow;
    device->RestoreWindow = qnxgf_restorewindow;
    device->SetWindowGrab = qnxgf_setwindowgrab;
    device->DestroyWindow = qnxgf_destroywindow;
    device->GetWindowWMInfo = qnxgf_getwindowwminfo;
    device->GL_LoadLibrary = qnxgf_gl_loadlibrary;
    device->GL_GetProcAddress = qnxgf_gl_getprocaddres;
    device->GL_UnloadLibrary = qnxgf_gl_unloadlibrary;
    device->GL_CreateContext = qnxgf_gl_createcontext;
    device->GL_MakeCurrent = qnxgf_gl_makecurrent;
    device->GL_SetSwapInterval = qnxgf_gl_setswapinterval;
    device->GL_GetSwapInterval = qnxgf_gl_getswapinterval;
    device->GL_SwapWindow = qnxgf_gl_swapwindow;
    device->GL_DeleteContext = qnxgf_gl_deletecontext;
    device->PumpEvents = qnxgf_pumpevents;
    device->SuspendScreenSaver = qnxgf_suspendscreensaver;

    return device;
}

VideoBootStrap qnxgf_bootstrap = {
    "qnxgf",
    "SDL QNX Graphics Framework (GF) video driver",
    qnxgf_available,
    qnxgf_create
};

/*****************************************************************************/
/* SDL Video and Display initialization/handling functions                   */
/*****************************************************************************/
int
qnxgf_videoinit(_THIS)
{
    SDL_VideoData *gfdata = (SDL_VideoData *) _this->driverdata;
    uint32_t it;
    uint32_t jt;
    char *override;
    int32_t status;

    /* By default GF uses buffer swap on vsync */
    gfdata->swapinterval = 1;

    /* Add each detected output to SDL */
    for (it = 0; it < gfdata->gfdev_info.ndisplays; it++) {
        SDL_VideoDisplay display;
        SDL_DisplayMode current_mode;
        SDL_DisplayData *didata;

        didata = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData));
        if (didata == NULL) {
            /* memory allocation problem */
            SDL_OutOfMemory();
            return -1;
        }

        /* Set default cursor settings, maximum 128x128 cursor */
        didata->cursor_visible = SDL_FALSE;
        didata->cursor.type = GF_CURSOR_BITMAP;
        didata->cursor.hotspot.x = 0;
        didata->cursor.hotspot.y = 0;
        didata->cursor.cursor.bitmap.w = SDL_VIDEO_GF_MAX_CURSOR_SIZE;
        didata->cursor.cursor.bitmap.h = SDL_VIDEO_GF_MAX_CURSOR_SIZE;
        didata->cursor.cursor.bitmap.stride =
            (didata->cursor.cursor.bitmap.w + 7) / (sizeof(uint8_t) * 8);
        didata->cursor.cursor.bitmap.color0 = 0x00000000;
        didata->cursor.cursor.bitmap.color1 = 0x00000000;
        didata->cursor.cursor.bitmap.image0 =
            SDL_calloc(sizeof(uint8_t),
                       (didata->cursor.cursor.bitmap.w +
                        7) * didata->cursor.cursor.bitmap.h /
                       (sizeof(uint8_t) * 8));
        if (didata->cursor.cursor.bitmap.image0 == NULL) {
            SDL_free(didata);
            SDL_OutOfMemory();
            return -1;
        }
        didata->cursor.cursor.bitmap.image1 =
            SDL_calloc(sizeof(uint8_t),
                       (didata->cursor.cursor.bitmap.w +
                        7) * didata->cursor.cursor.bitmap.h /
                       (sizeof(uint8_t) * 8));
        if (didata->cursor.cursor.bitmap.image1 == NULL) {
            SDL_OutOfMemory();
            SDL_free((void *) didata->cursor.cursor.bitmap.image0);
            SDL_free(didata);
            return -1;
        }

        /* Query current display settings */
        status = gf_display_query(gfdata->gfdev, it, &didata->display_info);
        if (status == GF_ERR_OK) {
            SDL_zero(current_mode);
            current_mode.w = didata->display_info.xres;
            current_mode.h = didata->display_info.yres;
            current_mode.refresh_rate = didata->display_info.refresh;
            current_mode.format =
                qnxgf_gf_to_sdl_pixelformat(didata->display_info.format);
            current_mode.driverdata = NULL;
        } else {
            /* video initialization problem */
            SDL_free((void *) didata->cursor.cursor.bitmap.image0);
            SDL_free((void *) didata->cursor.cursor.bitmap.image1);
            SDL_free(didata);
            SDL_SetError("GF: Display query failed");
            return -1;
        }

        /* Attach GF to selected display */
        status = gf_display_attach(&didata->display, gfdata->gfdev, it, NULL);
        if (status != GF_ERR_OK) {
            /* video initialization problem */
            SDL_free((void *) didata->cursor.cursor.bitmap.image0);
            SDL_free((void *) didata->cursor.cursor.bitmap.image1);
            SDL_free(didata);
            SDL_SetError("GF: Couldn't attach to display");
            return -1;
        }

        /* Initialize status variables */
        didata->layer_attached = SDL_FALSE;

        /* Attach to main display layer */
        status =
            gf_layer_attach(&didata->layer, didata->display,
                            didata->display_info.main_layer_index, 0);
        if (status != GF_ERR_OK) {
            /* Failed to attach to main layer */
            SDL_free((void *) didata->cursor.cursor.bitmap.image0);
            SDL_free((void *) didata->cursor.cursor.bitmap.image1);
            SDL_free(didata);
            SDL_SetError
                ("GF: Couldn't attach to main layer, it could be busy");
            return -1;
        }

        /* Mark main display layer is attached */
        didata->layer_attached = SDL_TRUE;

        /* Set layer source and destination viewport */
        gf_layer_set_src_viewport(didata->layer, 0, 0, current_mode.w - 1,
                                  current_mode.h - 1);
        gf_layer_set_dst_viewport(didata->layer, 0, 0, current_mode.w - 1,
                                  current_mode.h - 1);

        /* Create main visible on display surface */
        status = gf_surface_create_layer(&didata->surface[0], &didata->layer,
                                         1, 0, current_mode.w, current_mode.h,
                                         qnxgf_sdl_to_gf_pixelformat
                                         (current_mode.format), NULL,
                                         GF_SURFACE_CREATE_2D_ACCESSIBLE |
                                         GF_SURFACE_CREATE_3D_ACCESSIBLE |
                                         GF_SURFACE_CREATE_SHAREABLE);
        if (status != GF_ERR_OK) {
            gf_layer_disable(didata->layer);
            gf_layer_detach(didata->layer);
            didata->layer_attached = SDL_FALSE;
            SDL_free((void *) didata->cursor.cursor.bitmap.image0);
            SDL_free((void *) didata->cursor.cursor.bitmap.image1);
            SDL_free(didata);
            SDL_SetError("GF: Can't create main layer surface at init (%d)\n",
                         status);
            return -1;
        }

        /* Set just created surface as main visible on the layer */
//      gf_layer_set_surfaces(didata->layer, &didata->surface[0], 1);

        /* Update layer parameters */
        status = gf_layer_update(didata->layer, GF_LAYER_UPDATE_NO_WAIT_IDLE);
        if (status != GF_ERR_OK) {
            /* Free allocated surface */
            gf_surface_free(didata->surface[0]);
            didata->surface[0] = NULL;

            /* Disable and detach from layer */
            gf_layer_disable(didata->layer);
            gf_layer_detach(didata->layer);
            didata->layer_attached = SDL_FALSE;
            SDL_free((void *) didata->cursor.cursor.bitmap.image0);
            SDL_free((void *) didata->cursor.cursor.bitmap.image1);
            SDL_free(didata);
            SDL_SetError("GF: Can't update layer parameters\n");
            return -1;
        }

        /* Enable layer in case if hardware supports layer enable/disable */
        gf_layer_enable(didata->layer);

        /* Copy device name for each display */
        SDL_strlcpy(didata->description, gfdata->gfdev_info.description,
                    SDL_VIDEO_GF_DEVICENAME_MAX - 1);

        /* Search device capabilities and possible workarounds */
        jt = 0;
        do {
            if (gf_devicename[jt].name == NULL) {
                break;
            }
            if (SDL_strncmp
                (gf_devicename[jt].name, didata->description,
                 SDL_strlen(gf_devicename[jt].name)) == 0) {
                didata->caps = gf_devicename[jt].caps;
            }
            jt++;
        } while (1);

        /* Initialize display structure */
        SDL_zero(display);
        display.desktop_mode = current_mode;
        display.current_mode = current_mode;
        display.driverdata = didata;
        didata->current_mode = current_mode;
        SDL_AddVideoDisplay(&display);

        /* Check for environment variables which could override some SDL settings */
        didata->custom_refresh = 0;
        override = SDL_getenv("SDL_VIDEO_GF_REFRESH_RATE");
        if (override != NULL) {
            if (SDL_sscanf(override, "%u", &didata->custom_refresh) != 1) {
                didata->custom_refresh = 0;
            }
        }

        /* Get all display modes for this display */
        _this->current_display = it;
        qnxgf_getdisplaymodes(_this);
    }

    /* Restore default display */
    _this->current_display = 0;

    /* Add GF renderer to SDL */
    gf_addrenderdriver(_this);

    /* Add GF input devices */
    status = gf_addinputdevices(_this);
    if (status != 0) {
        /* SDL error is set by gf_addinputdevices() function */
        return -1;
    }

    /* video has been initialized successfully */
    return 1;
}

void
qnxgf_videoquit(_THIS)
{
    SDL_DisplayData *didata = NULL;
    uint32_t it;

    /* Stop collecting mouse events */
    hiddi_disable_mouse();
    /* Delete GF input devices */
    gf_delinputdevices(_this);

    /* SDL will restore old desktop mode on exit */
    for (it = 0; it < _this->num_displays; it++) {
        didata = _this->displays[it].driverdata;

        /* Free cursor image */
        if (didata->cursor.cursor.bitmap.image0 != NULL) {
            SDL_free((void *) didata->cursor.cursor.bitmap.image0);
            didata->cursor.cursor.bitmap.image0 = NULL;
        }
        if (didata->cursor.cursor.bitmap.image1 != NULL) {
            SDL_free((void *) didata->cursor.cursor.bitmap.image1);
            didata->cursor.cursor.bitmap.image1 = NULL;
        }

        /* Free main surface */
        if (didata->surface[0] != NULL) {
            gf_surface_free(didata->surface[0]);
            didata->surface[0] = NULL;
        }

        /* Free back surface */
        if (didata->surface[1] != NULL) {
            gf_surface_free(didata->surface[1]);
            didata->surface[1] = NULL;
        }

        /* Free second back surface */
        if (didata->surface[2] != NULL) {
            gf_surface_free(didata->surface[2]);
            didata->surface[2] = NULL;
        }

        /* Detach layer before quit */
        if (didata->layer_attached == SDL_TRUE) {
            /* Disable layer if hardware supports this */
            gf_layer_disable(didata->layer);

            /* Detach from layer, free it for others */
            gf_layer_detach(didata->layer);
            didata->layer = NULL;

            /* Mark it as detached */
            didata->layer_attached = SDL_FALSE;
        }

        /* Detach from selected display */
        gf_display_detach(didata->display);
        didata->display = NULL;
    }
}

void
qnxgf_getdisplaymodes(_THIS)
{
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    SDL_DisplayMode mode;
    gf_modeinfo_t modeinfo;
    uint32_t it = 0;
    uint32_t jt = 0;
    uint32_t kt = 0;
    int status;

    do {
        status = gf_display_query_mode(didata->display, it, &modeinfo);
        if (status == GF_ERR_OK) {
            /* Parsing current mode */
            if ((modeinfo.flags & GF_MODE_GENERIC) == GF_MODE_GENERIC) {
                /* This mode is generic, so we can add to SDL our resolutions */
                /* Only pixel format is fixed, refresh rate could be any      */
                jt = 0;
                do {
                    if (generic_mode[jt].w == 0) {
                        break;
                    }

                    /* Check if driver do not supports doublescan video modes */
                    if ((didata->caps & SDL_GF_LOWRESOLUTION) !=
                        SDL_GF_LOWRESOLUTION) {
                        if (generic_mode[jt].w < 640) {
                            jt++;
                            continue;
                        }
                    }

                    mode.w = generic_mode[jt].w;
                    mode.h = generic_mode[jt].h;
                    mode.refresh_rate = generic_mode[jt].refresh_rate;
                    mode.format =
                        qnxgf_gf_to_sdl_pixelformat(modeinfo.primary_format);
                    mode.driverdata = NULL;
                    SDL_AddDisplayMode(_this->current_display, &mode);

                    jt++;
                } while (1);
            } else {
                /* Add this display mode as is in case if it is non-generic */
                /* But go through the each refresh rate, supported by gf    */
                jt = 0;
                do {
                    if (modeinfo.refresh[jt] != 0) {
                        mode.w = modeinfo.xres;
                        mode.h = modeinfo.yres;
                        mode.refresh_rate = modeinfo.refresh[jt];
                        mode.format =
                            qnxgf_gf_to_sdl_pixelformat(modeinfo.
                                                        primary_format);
                        mode.driverdata = NULL;
                        SDL_AddDisplayMode(_this->current_display, &mode);
                        jt++;
                    } else {
                        break;
                    }
                } while (1);
            }
        } else {
            if (status == GF_ERR_PARM) {
                /* out of available modes, all are listed */
                break;
            }

            /* Error occured during mode listing */
            break;
        }
        it++;
    } while (1);
}

int
qnxgf_setdisplaymode(_THIS, SDL_DisplayMode * mode)
{
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    uint32_t refresh_rate = 0;
    int status;

    /* Current display dimensions and bpp are no more valid */
    didata->current_mode.format = SDL_PIXELFORMAT_UNKNOWN;
    didata->current_mode.w = 0;
    didata->current_mode.h = 0;

    /* Check if custom refresh rate requested */
    if (didata->custom_refresh != 0) {
        refresh_rate = didata->custom_refresh;
    } else {
        refresh_rate = mode->refresh_rate;
    }

    /* Check if SDL GF driver needs to find appropriate refresh rate itself */
    if (refresh_rate == 0) {
        uint32_t it;
        SDL_DisplayMode tempmode;

        /* Clear display mode structure */
        SDL_memset(&tempmode, 0x00, sizeof(SDL_DisplayMode));
        tempmode.refresh_rate = 0x0000FFFF;

        /* Check if window width and height matches one of our modes */
        for (it = 0; it < SDL_CurrentDisplay.num_display_modes; it++) {
            if ((SDL_CurrentDisplay.display_modes[it].w == mode->w) &&
                (SDL_CurrentDisplay.display_modes[it].h == mode->h) &&
                (SDL_CurrentDisplay.display_modes[it].format == mode->format))
            {
                /* Find the lowest refresh rate available */
                if (tempmode.refresh_rate >
                    SDL_CurrentDisplay.display_modes[it].refresh_rate) {
                    tempmode = SDL_CurrentDisplay.display_modes[it];
                }
            }
        }
        if (tempmode.refresh_rate != 0x0000FFFF) {
            refresh_rate = tempmode.refresh_rate;
        } else {
            /* Let video driver decide what to do with this */
            refresh_rate = 0;
        }
    }

    /* Check if SDL GF driver needs to check custom refresh rate */
    if (didata->custom_refresh != 0) {
        uint32_t it;
        SDL_DisplayMode tempmode;

        /* Clear display mode structure */
        SDL_memset(&tempmode, 0x00, sizeof(SDL_DisplayMode));
        tempmode.refresh_rate = 0x0000FFFF;

        /* Check if window width and height matches one of our modes */
        for (it = 0; it < SDL_CurrentDisplay.num_display_modes; it++) {
            if ((SDL_CurrentDisplay.display_modes[it].w == mode->w) &&
                (SDL_CurrentDisplay.display_modes[it].h == mode->h) &&
                (SDL_CurrentDisplay.display_modes[it].format == mode->format))
            {
                /* Find the lowest refresh rate available */
                if (tempmode.refresh_rate >
                    SDL_CurrentDisplay.display_modes[it].refresh_rate) {
                    tempmode = SDL_CurrentDisplay.display_modes[it];
                }

                /* Check if requested refresh rate found */
                if (refresh_rate ==
                    SDL_CurrentDisplay.display_modes[it].refresh_rate) {
                    tempmode = SDL_CurrentDisplay.display_modes[it];
                    break;
                }
            }
        }
        if (tempmode.refresh_rate != 0x0000FFFF) {
            refresh_rate = tempmode.refresh_rate;
        } else {
            /* Let video driver decide what to do with this */
            refresh_rate = 0;
        }
    }

    /* Free main surface */
    if (didata->surface[0] != NULL) {
        gf_surface_free(didata->surface[0]);
        didata->surface[0] = NULL;
    }

    /* Free back surface */
    if (didata->surface[1] != NULL) {
        gf_surface_free(didata->surface[1]);
        didata->surface[1] = NULL;
    }

    /* Free second back surface */
    if (didata->surface[2] != NULL) {
        gf_surface_free(didata->surface[2]);
        didata->surface[2] = NULL;
    }

    /* Detach layer before switch to new graphics mode */
    if (didata->layer_attached == SDL_TRUE) {
        /* Disable layer if hardware supports this */
        gf_layer_disable(didata->layer);

        /* Detach from layer, free it for others */
        gf_layer_detach(didata->layer);

        /* Mark it as detached */
        didata->layer_attached = SDL_FALSE;
    }

    /* Set new display video mode */
    status =
        gf_display_set_mode(didata->display, mode->w, mode->h, refresh_rate,
                            qnxgf_sdl_to_gf_pixelformat(mode->format), 0);
    if (status != GF_ERR_OK) {
        /* Display mode/resolution switch has been failed */
        SDL_SetError("GF: Mode is not supported by graphics driver");
        return -1;
    } else {
        didata->current_mode = *mode;
        didata->current_mode.refresh_rate = refresh_rate;
    }

    /* Attach to main display layer */
    status =
        gf_layer_attach(&didata->layer, didata->display,
                        didata->display_info.main_layer_index, 0);
    if (status != GF_ERR_OK) {
        SDL_SetError("GF: Couldn't attach to main layer, it could be busy");

        /* Failed to attach to main displayable layer */
        return -1;
    }

    /* Mark main display layer is attached */
    didata->layer_attached = SDL_TRUE;

    /* Set layer source and destination viewport */
    gf_layer_set_src_viewport(didata->layer, 0, 0, mode->w - 1, mode->h - 1);
    gf_layer_set_dst_viewport(didata->layer, 0, 0, mode->w - 1, mode->h - 1);

    /* Create main visible on display surface */
    status =
        gf_surface_create_layer(&didata->surface[0], &didata->layer, 1, 0,
                                mode->w, mode->h,
                                qnxgf_sdl_to_gf_pixelformat(mode->format),
                                NULL,
                                GF_SURFACE_CREATE_2D_ACCESSIBLE |
                                GF_SURFACE_CREATE_3D_ACCESSIBLE |
                                GF_SURFACE_CREATE_SHAREABLE);
    if (status != GF_ERR_OK) {
        gf_layer_disable(didata->layer);
        gf_layer_detach(didata->layer);
        didata->layer_attached = SDL_FALSE;
        SDL_SetError
            ("GF: Can't create main layer surface at modeswitch (%d)\n",
             status);
        return -1;
    }

    /* Set just created surface as main visible on the layer */
    gf_layer_set_surfaces(didata->layer, &didata->surface[0], 1);

    /* Update layer parameters */
    status = gf_layer_update(didata->layer, GF_LAYER_UPDATE_NO_WAIT_IDLE);
    if (status != GF_ERR_OK) {
        /* Free main surface */
        gf_surface_free(didata->surface[0]);
        didata->surface[0] = NULL;

        /* Detach layer */
        gf_layer_disable(didata->layer);
        gf_layer_detach(didata->layer);
        didata->layer_attached = SDL_FALSE;
        SDL_SetError("GF: Can't update layer parameters\n");
        return -1;
    }

    /* Restore cursor if it was visible */
    if (didata->cursor_visible == SDL_TRUE) {
        gf_cursor_set(didata->display, 0, &didata->cursor);
        gf_cursor_enable(didata->display, 0);
    }

    /* Enable layer in case if hardware supports layer enable/disable */
    gf_layer_enable(didata->layer);

    return 0;
}

int
qnxgf_setdisplaypalette(_THIS, SDL_Palette * palette)
{
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;

    /* QNX GF doesn't have support for global palette changing, but we */
    /* could store it for usage in future */

    /* Setting display palette operation has been failed */
    return -1;
}

int
qnxgf_getdisplaypalette(_THIS, SDL_Palette * palette)
{
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;

    /* We can't provide current palette settings and looks like SDL          */
    /* do not call this function also, in such case this function returns -1 */

    /* Getting display palette operation has been failed */
    return -1;
}

int
qnxgf_setdisplaygammaramp(_THIS, Uint16 * ramp)
{
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    int status;

    /* Setup gamma ramp, for each color channel */
    status =
        gf_display_set_color_lut16(didata->display, (uint16_t *) ramp,
                                   (uint16_t *) ramp + 256,
                                   (uint16_t *) ramp + 512);
    if (status != GF_ERR_OK) {
        /* Setting display gamma ramp operation has been failed */
        return -1;
    }

    return 0;
}

int
qnxgf_getdisplaygammaramp(_THIS, Uint16 * ramp)
{
    /* TODO: We need to return previous gamma set           */
    /*       Also we need some initial fake gamma to return */

    /* Getting display gamma ramp operation has been failed */
    return -1;
}

int
qnxgf_createwindow(_THIS, SDL_Window * window)
{
    SDL_VideoData *gfdata = (SDL_VideoData *) _this->driverdata;
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    SDL_WindowData *wdata;
    int32_t status;

    /* QNX GF supports fullscreen window modes only */
    if ((window->flags & SDL_WINDOW_FULLSCREEN) != SDL_WINDOW_FULLSCREEN) {
        uint32_t it;
        SDL_DisplayMode mode;

        /* Clear display mode structure */
        SDL_memset(&mode, 0x00, sizeof(SDL_DisplayMode));
        mode.refresh_rate = 0x0000FFFF;

        /* Check if window width and height matches one of our modes */
        for (it = 0; it < SDL_CurrentDisplay.num_display_modes; it++) {
            if ((SDL_CurrentDisplay.display_modes[it].w == window->w) &&
                (SDL_CurrentDisplay.display_modes[it].h == window->h) &&
                (SDL_CurrentDisplay.display_modes[it].format ==
                 SDL_CurrentDisplay.desktop_mode.format)) {
                /* Find the lowest refresh rate available */
                if (mode.refresh_rate >
                    SDL_CurrentDisplay.display_modes[it].refresh_rate) {
                    mode = SDL_CurrentDisplay.display_modes[it];
                }
            }
        }

        /* Check if end of display list has been reached */
        if (mode.refresh_rate == 0x0000FFFF) {
            SDL_SetError("GF: Desired video mode is not supported");

            /* Failed to create new window */
            return -1;
        } else {
            /* Tell to the caller that mode will be fullscreen */
            window->flags |= SDL_WINDOW_FULLSCREEN;

            /* Setup fullscreen mode, bpp used from desktop mode in this case */
            status = qnxgf_setdisplaymode(_this, &mode);
            if (status != 0) {
                /* Failed to swith fullscreen video mode */
                return -1;
            }
        }
    }

    /* Setup our own window decorations and states, which are depend on fullscreen mode */
    window->flags |= SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS |
        SDL_WINDOW_MAXIMIZED | SDL_WINDOW_INPUT_GRABBED |
        SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS;
    window->flags &= ~(SDL_WINDOW_RESIZABLE | SDL_WINDOW_MINIMIZED);

    /* Ignore any window position settings */
    window->x = SDL_WINDOWPOS_UNDEFINED;
    window->y = SDL_WINDOWPOS_UNDEFINED;

    /* Allocate window internal data */
    wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
    if (wdata == NULL) {
        SDL_OutOfMemory();
        return -1;
    }

    /* Setup driver data for this window */
    window->driverdata = wdata;

    /* Check if window must support OpenGL ES rendering */
    if ((window->flags & SDL_WINDOW_OPENGL) == SDL_WINDOW_OPENGL) {
#if defined(SDL_VIDEO_OPENGL_ES)
        EGLBoolean initstatus;

        /* Mark this window as OpenGL ES compatible */
        wdata->uses_gles = SDL_TRUE;

        /* Create connection to OpenGL ES */
        if (gfdata->egldisplay == EGL_NO_DISPLAY) {
            gfdata->egldisplay = eglGetDisplay(gfdata->gfdev);
            if (gfdata->egldisplay == EGL_NO_DISPLAY) {
                SDL_SetError("GF: Can't get connection to OpenGL ES");
                return -1;
            }

            /* Initialize OpenGL ES library, ignore EGL version */
            initstatus = eglInitialize(gfdata->egldisplay, NULL, NULL);
            if (initstatus != EGL_TRUE) {
                SDL_SetError("GF: Can't init OpenGL ES library");
                return -1;
            }
        }

        /* Increment GL ES reference count usage */
        gfdata->egl_refcount++;
#else
        SDL_SetError("GF: OpenGL ES support is not compiled in");
        return -1;
#endif /* SDL_VIDEO_OPENGL_ES */
    }

    /* Enable mouse event collecting */
    hiddi_enable_mouse();

    /* By default last created window got a input focus */
    SDL_SetKeyboardFocus(0, window->id);
    SDL_SetMouseFocus(0, window->id);

    /* Window has been successfully created */
    return 0;
}

int
qnxgf_createwindowfrom(_THIS, SDL_Window * window, const void *data)
{
    /* Failed to create window from another window */
    return -1;
}

void
qnxgf_setwindowtitle(_THIS, SDL_Window * window)
{
}

void
qnxgf_setwindowicon(_THIS, SDL_Window * window, SDL_Surface * icon)
{
}

void
qnxgf_setwindowposition(_THIS, SDL_Window * window)
{
}

void
qnxgf_setwindowsize(_THIS, SDL_Window * window)
{
}

void
qnxgf_showwindow(_THIS, SDL_Window * window)
{
}

void
qnxgf_hidewindow(_THIS, SDL_Window * window)
{
}

void
qnxgf_raisewindow(_THIS, SDL_Window * window)
{
}

void
qnxgf_maximizewindow(_THIS, SDL_Window * window)
{
}

void
qnxgf_minimizewindow(_THIS, SDL_Window * window)
{
}

void
qnxgf_restorewindow(_THIS, SDL_Window * window)
{
}

void
qnxgf_setwindowgrab(_THIS, SDL_Window * window)
{
}

void
qnxgf_destroywindow(_THIS, SDL_Window * window)
{
    SDL_VideoData *gfdata = (SDL_VideoData *) _this->driverdata;
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;

    if (wdata != NULL) {
#if defined(SDL_VIDEO_OPENGL_ES)
        /* Destroy OpenGL ES surface if it was created */
        if (wdata->gles_surface != EGL_NO_SURFACE) {
            eglDestroySurface(gfdata->egldisplay, wdata->gles_surface);
        }

        /* Free any 3D target if it was created before */
        if (wdata->target_created == SDL_TRUE) {
            gf_3d_target_free(wdata->target);
            wdata->target_created == SDL_FALSE;
        }

        gfdata->egl_refcount--;
        if (gfdata->egl_refcount == 0) {
            /* Terminate connection to OpenGL ES */
            if (gfdata->egldisplay != EGL_NO_DISPLAY) {
                eglTerminate(gfdata->egldisplay);
                gfdata->egldisplay = EGL_NO_DISPLAY;
            }
        }
#endif /* SDL_VIDEO_OPENGL_ES */
    }
}

/*****************************************************************************/
/* SDL Window Manager function                                               */
/*****************************************************************************/
SDL_bool
qnxgf_getwindowwminfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info)
{
    /* QNX GF do not operates at window level, this means we are have no */
    /* Window Manager available, no specific data in SDL_SysWMinfo too   */

    if (info->version.major <= SDL_MAJOR_VERSION) {
        return SDL_TRUE;
    } else {
        SDL_SetError("Application not compiled with SDL %d.%d\n",
                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
        return SDL_FALSE;
    }

    /* Failed to get window manager information */
    return SDL_FALSE;
}

/*****************************************************************************/
/* SDL OpenGL/OpenGL ES functions                                            */
/*****************************************************************************/
int
qnxgf_gl_loadlibrary(_THIS, const char *path)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    /* Check if OpenGL ES library is specified for GF driver */
    if (path == NULL) {
        path = SDL_getenv("SDL_OPENGL_LIBRARY");
        if (path == NULL) {
            path = SDL_getenv("SDL_OPENGLES_LIBRARY");
        }
    }

    /* Check if default library loading requested */
    if (path == NULL) {
        /* Already linked with GF library which provides egl* subset of  */
        /* functions, use Common profile of OpenGL ES library by default */
        path = "/usr/lib/libGLES_CM.so.1";
    }

    /* Load dynamic library */
    _this->gl_config.dll_handle = SDL_LoadObject(path);
    if (!_this->gl_config.dll_handle) {
        /* Failed to load new GL ES library */
        SDL_SetError("GF: Failed to locate OpenGL ES library");
        return -1;
    }

    /* Store OpenGL ES library path and name */
    SDL_strlcpy(_this->gl_config.driver_path, path,
                SDL_arraysize(_this->gl_config.driver_path));

    /* New OpenGL ES library is loaded */
    return 0;
#else
    SDL_SetError("GF: OpenGL ES support is not compiled in");
    return -1;
#endif /* SDL_VIDEO_OPENGL_ES */
}

void *
qnxgf_gl_getprocaddres(_THIS, const char *proc)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    void *function_address;

    /* Try to get function address through the egl interface */
    function_address = eglGetProcAddress(proc);
    if (function_address != NULL) {
        return function_address;
    }

    /* Then try to get function in the OpenGL ES library */
    if (_this->gl_config.dll_handle) {
        function_address =
            SDL_LoadFunction(_this->gl_config.dll_handle, proc);
        if (function_address != NULL) {
            return function_address;
        }
    }

    /* Add emulated OpenGL ES 1.1 functions */
    if (SDL_strcmp(proc, "glTexParameteri") == 0) {
        return glTexParameteri;
    }
    if (SDL_strcmp(proc, "glTexParameteriv") == 0) {
        return glTexParameteriv;
    }
    if (SDL_strcmp(proc, "glColor4ub") == 0) {
        return glColor4ub;
    }

    /* Failed to get GL ES function address pointer */
    SDL_SetError("GF: Cannot locate OpenGL ES function name");
    return NULL;
#else
    SDL_SetError("GF: OpenGL ES support is not compiled in");
    return NULL;
#endif /* SDL_VIDEO_OPENGL_ES */
}

void
qnxgf_gl_unloadlibrary(_THIS)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    /* Unload OpenGL ES library */
    if (_this->gl_config.dll_handle) {
        SDL_UnloadObject(_this->gl_config.dll_handle);
        _this->gl_config.dll_handle = NULL;
    }
#else
    SDL_SetError("GF: OpenGL ES support is not compiled in");
    return;
#endif /* SDL_VIDEO_OPENGL_ES */
}

SDL_GLContext
qnxgf_gl_createcontext(_THIS, SDL_Window * window)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *gfdata = (SDL_VideoData *) _this->driverdata;
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
    SDL_DisplayData *didata =
        (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
    EGLBoolean status;
    int32_t gfstatus;
    EGLint configs;
    uint32_t surfaces;
    uint32_t attr_pos;
    EGLint attr_value;
    EGLint cit;

    /* Choose buffeingr scheme */
    if (!_this->gl_config.double_buffer) {
        surfaces = 1;
    } else {
        surfaces = 2;
    }

    /* If driver has no support of video memory allocation, then */
    /* disable double buffering, use single buffer present copy  */
    if ((didata->caps & SDL_GF_VIDEOMEMORY) != SDL_GF_VIDEOMEMORY) {
        surfaces = 1;
    }

    /* Free main surface */
    if (didata->surface[0] != NULL) {
        gf_surface_free(didata->surface[0]);
        didata->surface[0] = NULL;
    }

    /* Free back surface */
    if (didata->surface[1] != NULL) {
        gf_surface_free(didata->surface[1]);
        didata->surface[1] = NULL;
    }

    /* Free second back surface */
    if (didata->surface[2] != NULL) {
        gf_surface_free(didata->surface[2]);
        didata->surface[2] = NULL;
    }

    /* Detach layer before switch to new graphics mode */
    if (didata->layer_attached == SDL_TRUE) {
        /* Disable layer if hardware supports this */
        gf_layer_disable(didata->layer);

        /* Detach from layer, free it for others */
        gf_layer_detach(didata->layer);

        /* Mark it as detached */
        didata->layer_attached = SDL_FALSE;
    }

    /* Attach to main display layer */
    gfstatus =
        gf_layer_attach(&didata->layer, didata->display,
                        didata->display_info.main_layer_index, 0);
    if (gfstatus != GF_ERR_OK) {
        SDL_SetError("GF: Couldn't attach to main layer, it could be busy");

        /* Failed to attach to main displayable layer */
        return NULL;
    }

    /* Mark main display layer is attached */
    didata->layer_attached = SDL_TRUE;

    /* Set layer source and destination viewport */
    gf_layer_set_src_viewport(didata->layer, 0, 0, didata->current_mode.w - 1,
                              didata->current_mode.h - 1);
    gf_layer_set_dst_viewport(didata->layer, 0, 0, didata->current_mode.w - 1,
                              didata->current_mode.h - 1);

    /* Create main visible on display surface */
    gfstatus =
        gf_surface_create_layer(&didata->surface[0], &didata->layer, 1, 0,
                                didata->current_mode.w,
                                didata->current_mode.h,
                                qnxgf_sdl_to_gf_pixelformat(didata->
                                                            current_mode.
                                                            format), NULL,
                                GF_SURFACE_CREATE_2D_ACCESSIBLE |
                                GF_SURFACE_CREATE_3D_ACCESSIBLE |
                                GF_SURFACE_CREATE_SHAREABLE);
    if (gfstatus != GF_ERR_OK) {
        gf_layer_disable(didata->layer);
        gf_layer_detach(didata->layer);
        didata->layer_attached = SDL_FALSE;
        SDL_SetError("GF: Can't create main layer surface at glctx (%d)\n",
                     gfstatus);
        return NULL;
    }

    /* Set just created surface as main visible on the layer */
//      gf_layer_set_surfaces(didata->layer, &didata->surface[0], 1);

    if (surfaces > 1) {
        /* Create back display surface */
        gfstatus =
            gf_surface_create_layer(&didata->surface[1], &didata->layer, 1, 0,
                                    didata->current_mode.w,
                                    didata->current_mode.h,
                                    qnxgf_sdl_to_gf_pixelformat(didata->
                                                                current_mode.
                                                                format), NULL,
                                    GF_SURFACE_CREATE_2D_ACCESSIBLE |
                                    GF_SURFACE_CREATE_3D_ACCESSIBLE |
                                    GF_SURFACE_CREATE_SHAREABLE);
        if (gfstatus != GF_ERR_OK) {
            gf_surface_free(didata->surface[0]);
            gf_layer_disable(didata->layer);
            gf_layer_detach(didata->layer);
            didata->layer_attached = SDL_FALSE;
            SDL_SetError
                ("GF: Can't create main layer surface at glctx (%d)\n",
                 gfstatus);
            return NULL;
        }
    }

    /* Update layer parameters */
    gfstatus = gf_layer_update(didata->layer, GF_LAYER_UPDATE_NO_WAIT_IDLE);
    if (gfstatus != GF_ERR_OK) {
        /* Free main and back surfaces */
        gf_surface_free(didata->surface[1]);
        didata->surface[1] = NULL;
        gf_surface_free(didata->surface[0]);
        didata->surface[0] = NULL;

        /* Detach layer */
        gf_layer_disable(didata->layer);
        gf_layer_detach(didata->layer);
        didata->layer_attached = SDL_FALSE;
        SDL_SetError("GF: Can't update layer parameters\n");
        return NULL;
    }

    /* Enable layer in case if hardware supports layer enable/disable */
    gf_layer_enable(didata->layer);

    /* Prepare attributes list to pass them to OpenGL ES */
    attr_pos = 0;
    wdata->gles_attributes[attr_pos++] = EGL_NATIVE_VISUAL_ID;
    wdata->gles_attributes[attr_pos++] =
        qnxgf_sdl_to_gf_pixelformat(didata->current_mode.format);
    wdata->gles_attributes[attr_pos++] = EGL_RED_SIZE;
    wdata->gles_attributes[attr_pos++] = _this->gl_config.red_size;
    wdata->gles_attributes[attr_pos++] = EGL_GREEN_SIZE;
    wdata->gles_attributes[attr_pos++] = _this->gl_config.green_size;
    wdata->gles_attributes[attr_pos++] = EGL_BLUE_SIZE;
    wdata->gles_attributes[attr_pos++] = _this->gl_config.blue_size;
    wdata->gles_attributes[attr_pos++] = EGL_ALPHA_SIZE;
    if (_this->gl_config.alpha_size) {
        wdata->gles_attributes[attr_pos++] = _this->gl_config.alpha_size;
    } else {
        wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
    }
    wdata->gles_attributes[attr_pos++] = EGL_DEPTH_SIZE;
    wdata->gles_attributes[attr_pos++] = _this->gl_config.depth_size;
    if (_this->gl_config.buffer_size) {
        wdata->gles_attributes[attr_pos++] = EGL_BUFFER_SIZE;
        wdata->gles_attributes[attr_pos++] = _this->gl_config.buffer_size;
    }
    if (_this->gl_config.stencil_size) {
        wdata->gles_attributes[attr_pos++] = EGL_STENCIL_SIZE;
        wdata->gles_attributes[attr_pos++] = _this->gl_config.buffer_size;
    }

    /* Set number of samples in multisampling */
    if (_this->gl_config.multisamplesamples) {
        wdata->gles_attributes[attr_pos++] = EGL_SAMPLES;
        wdata->gles_attributes[attr_pos++] =
            _this->gl_config.multisamplesamples;
    }

    /* Multisample buffers, OpenGL ES 1.0 spec defines 0 or 1 buffer */
    if (_this->gl_config.multisamplebuffers) {
        wdata->gles_attributes[attr_pos++] = EGL_SAMPLE_BUFFERS;
        wdata->gles_attributes[attr_pos++] =
            _this->gl_config.multisamplebuffers;
    }

    /* Finish attributes list */
    wdata->gles_attributes[attr_pos] = EGL_NONE;

    /* Request first suitable framebuffer configuration */
    status = eglChooseConfig(gfdata->egldisplay, wdata->gles_attributes,
                             wdata->gles_configs, SDL_VIDEO_GF_OPENGLES_CONFS,
                             &configs);
    if (status != EGL_TRUE) {
        SDL_SetError("GF: Can't find closest configuration for OpenGL ES");
        return NULL;
    }

    /* Check if nothing has been found, try "don't care" settings */
    if (configs == 0) {
        int32_t it;
        int32_t jt;
        GLint depthbits[4] = { 32, 24, 16, EGL_DONT_CARE };

        for (it = 0; it < 4; it++) {
            for (jt = 16; jt >= 0; jt--) {
                /* Don't care about color buffer bits, use what exist */
                /* Replace previous data set with EGL_DONT_CARE       */
                attr_pos = 0;
                wdata->gles_attributes[attr_pos++] = EGL_NATIVE_VISUAL_ID;
                wdata->gles_attributes[attr_pos++] =
                    qnxgf_sdl_to_gf_pixelformat(didata->current_mode.format);
                wdata->gles_attributes[attr_pos++] = EGL_RED_SIZE;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos++] = EGL_GREEN_SIZE;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos++] = EGL_BLUE_SIZE;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos++] = EGL_ALPHA_SIZE;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos++] = EGL_BUFFER_SIZE;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;

                /* Try to find requested or smallest depth */
                if (_this->gl_config.depth_size) {
                    wdata->gles_attributes[attr_pos++] = EGL_DEPTH_SIZE;
                    wdata->gles_attributes[attr_pos++] = depthbits[it];
                } else {
                    wdata->gles_attributes[attr_pos++] = EGL_DEPTH_SIZE;
                    wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                }

                if (_this->gl_config.stencil_size) {
                    wdata->gles_attributes[attr_pos++] = EGL_STENCIL_SIZE;
                    wdata->gles_attributes[attr_pos++] = jt;
                } else {
                    wdata->gles_attributes[attr_pos++] = EGL_STENCIL_SIZE;
                    wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;

                    /* exit from stencil loop */
                    jt = 0;
                }

                /* Don't care about antialiasing */
                wdata->gles_attributes[attr_pos++] = EGL_SAMPLES;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos++] = EGL_SAMPLE_BUFFERS;
                wdata->gles_attributes[attr_pos++] = EGL_DONT_CARE;
                wdata->gles_attributes[attr_pos] = EGL_NONE;

                /* Request first suitable framebuffer configuration */
                status =
                    eglChooseConfig(gfdata->egldisplay,
                                    wdata->gles_attributes,
                                    wdata->gles_configs,
                                    SDL_VIDEO_GF_OPENGLES_CONFS, &configs);
                if (status != EGL_TRUE) {
                    SDL_SetError
                        ("Photon: Can't find closest configuration for OpenGL ES");
                    return NULL;
                }
                if (configs != 0) {
                    break;
                }
            }
            if (configs != 0) {
                break;
            }
        }

        /* No available configs */
        if (configs == 0) {
            SDL_SetError
                ("Photon: Can't find any configuration for OpenGL ES");
            return NULL;
        }
    }

    /* Initialize config index */
    wdata->gles_config = 0;

    /* Now check each configuration to find out the best */
    for (cit = 0; cit < configs; cit++) {
        uint32_t stencil_found;
        uint32_t depth_found;

        stencil_found = 0;
        depth_found = 0;

        if (_this->gl_config.stencil_size) {
            status =
                eglGetConfigAttrib(gfdata->egldisplay,
                                   wdata->gles_configs[cit], EGL_STENCIL_SIZE,
                                   &attr_value);
            if (status == EGL_TRUE) {
                if (attr_value != 0) {
                    stencil_found = 1;
                }
            }
        } else {
            stencil_found = 1;
        }

        if (_this->gl_config.depth_size) {
            status =
                eglGetConfigAttrib(gfdata->egldisplay,
                                   wdata->gles_configs[cit], EGL_DEPTH_SIZE,
                                   &attr_value);
            if (status == EGL_TRUE) {
                if (attr_value != 0) {
                    depth_found = 1;
                }
            }
        } else {
            depth_found = 1;
        }

        /* Exit from loop if found appropriate configuration */
        if ((depth_found != 0) && (stencil_found != 0)) {
            break;
        }
    }

    /* If best could not be found, use first */
    if (cit == configs) {
        cit = 0;
    }
    wdata->gles_config = cit;

    /* Create OpenGL ES context */
    wdata->gles_context =
        eglCreateContext(gfdata->egldisplay,
                         wdata->gles_configs[wdata->gles_config],
                         EGL_NO_CONTEXT, NULL);
    if (wdata->gles_context == EGL_NO_CONTEXT) {
        SDL_SetError("GF: OpenGL ES context creation has been failed");
        return NULL;
    }

    /* Free any 3D target if it was created before */
    if (wdata->target_created == SDL_TRUE) {
        gf_3d_target_free(wdata->target);
        wdata->target_created == SDL_FALSE;
    }

    /* Create surface(s) target for OpenGL ES */
    gfstatus =
        gf_3d_target_create(&wdata->target, didata->layer,
                            &didata->surface[0], surfaces,
                            didata->current_mode.w, didata->current_mode.h,
                            qnxgf_sdl_to_gf_pixelformat(didata->current_mode.
                                                        format));
    if (gfstatus != GF_ERR_OK) {
        /* Destroy just created context */
        eglDestroyContext(gfdata->egldisplay, wdata->gles_context);
        wdata->gles_context = EGL_NO_CONTEXT;

        /* Mark 3D target as unallocated */
        wdata->target_created = SDL_FALSE;
        SDL_SetError("GF: OpenGL ES target could not be created");
        return NULL;
    } else {
        wdata->target_created = SDL_TRUE;
    }

    /* Create target rendering surface on whole screen */
    wdata->gles_surface =
        eglCreateWindowSurface(gfdata->egldisplay,
                               wdata->gles_configs[wdata->gles_config],
                               wdata->target, NULL);
    if (wdata->gles_surface == EGL_NO_SURFACE) {
        /* Destroy 3d target */
        gf_3d_target_free(wdata->target);
        wdata->target_created = SDL_FALSE;

        /* Destroy OpenGL ES context */
        eglDestroyContext(gfdata->egldisplay, wdata->gles_context);
        wdata->gles_context = EGL_NO_CONTEXT;

        SDL_SetError("GF: OpenGL ES surface could not be created");
        return NULL;
    }

    /* Make just created context current */
    status =
        eglMakeCurrent(gfdata->egldisplay, wdata->gles_surface,
                       wdata->gles_surface, wdata->gles_context);
    if (status != EGL_TRUE) {
        /* Destroy OpenGL ES surface */
        eglDestroySurface(gfdata->egldisplay, wdata->gles_surface);

        /* Destroy 3d target */
        gf_3d_target_free(wdata->target);
        wdata->target_created = SDL_FALSE;

        /* Destroy OpenGL ES context */
        eglDestroyContext(gfdata->egldisplay, wdata->gles_context);
        wdata->gles_context = EGL_NO_CONTEXT;

        /* Failed to set current GL ES context */
        SDL_SetError("GF: Can't set OpenGL ES context on creation");
        return NULL;
    }

    /* Setup into SDL internals state of OpenGL ES:  */
    /* it is accelerated or not                      */
    if ((didata->caps & SDL_GF_ACCELERATED_3D) == SDL_GF_ACCELERATED_3D) {
        _this->gl_config.accelerated = 1;
    } else {
        _this->gl_config.accelerated = 0;
    }

    /* Always clear stereo enable, since OpenGL ES do not supports stereo */
    _this->gl_config.stereo = 0;

    /* Get back samples and samplebuffers configurations. Rest framebuffer */
    /* parameters could be obtained through the OpenGL ES API              */
    status =
        eglGetConfigAttrib(gfdata->egldisplay,
                           wdata->gles_configs[wdata->gles_config],
                           EGL_SAMPLES, &attr_value);
    if (status == EGL_TRUE) {
        _this->gl_config.multisamplesamples = attr_value;
    }
    status =
        eglGetConfigAttrib(gfdata->egldisplay,
                           wdata->gles_configs[wdata->gles_config],
                           EGL_SAMPLE_BUFFERS, &attr_value);
    if (status == EGL_TRUE) {
        _this->gl_config.multisamplebuffers = attr_value;
    }

    /* Get back stencil and depth buffer sizes */
    status =
        eglGetConfigAttrib(gfdata->egldisplay,
                           wdata->gles_configs[wdata->gles_config],
                           EGL_DEPTH_SIZE, &attr_value);
    if (status == EGL_TRUE) {
        _this->gl_config.depth_size = attr_value;
    }
    status =
        eglGetConfigAttrib(gfdata->egldisplay,
                           wdata->gles_configs[wdata->gles_config],
                           EGL_STENCIL_SIZE, &attr_value);
    if (status == EGL_TRUE) {
        _this->gl_config.stencil_size = attr_value;
    }

    /* Restore cursor if it was visible */
    if (didata->cursor_visible == SDL_TRUE) {
        gf_cursor_set(didata->display, 0, &didata->cursor);
        gf_cursor_enable(didata->display, 0);
    }

    /* GL ES context was successfully created */
    return wdata->gles_context;
#else
    SDL_SetError("GF: OpenGL ES support is not compiled in");
    return NULL;
#endif /* SDL_VIDEO_OPENGL_ES */
}

int
qnxgf_gl_makecurrent(_THIS, SDL_Window * window, SDL_GLContext context)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *gfdata = (SDL_VideoData *) _this->driverdata;
    SDL_WindowData *wdata;
    EGLBoolean status;

    if ((window == NULL) && (context == NULL)) {
        status =
            eglMakeCurrent(gfdata->egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
                           EGL_NO_CONTEXT);
        if (status != EGL_TRUE) {
            /* Failed to set current GL ES context */
            SDL_SetError("GF: Can't set OpenGL ES context");
            return -1;
        }
    } else {
        wdata = (SDL_WindowData *) window->driverdata;
        status =
            eglMakeCurrent(gfdata->egldisplay, wdata->gles_surface,
                           wdata->gles_surface, wdata->gles_context);
        if (status != EGL_TRUE) {
            /* Failed to set current GL ES context */
            SDL_SetError("GF: Can't set OpenGL ES context");
            return -1;
        }
    }

    return 0;
#else
    SDL_SetError("GF: OpenGL ES support is not compiled in");
    return -1;
#endif /* SDL_VIDEO_OPENGL_ES */
}

int
qnxgf_gl_setswapinterval(_THIS, int interval)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *gfdata = (SDL_VideoData *) _this->driverdata;
    EGLBoolean status;

    /* Check if OpenGL ES connection has been initialized */
    if (gfdata->egldisplay != EGL_NO_DISPLAY) {
        /* Set swap OpenGL ES interval */
        status = eglSwapInterval(gfdata->egldisplay, interval);
        if (status == EGL_TRUE) {
            /* Return success to upper level */
            gfdata->swapinterval = interval;
            return 0;
        }
    }

    /* Failed to set swap interval */
    SDL_SetError("GF: Cannot set swap interval");
    return -1;
#else
    SDL_SetError("GF: OpenGL ES support is not compiled in");
    return -1;
#endif /* SDL_VIDEO_OPENGL_ES */
}

int
qnxgf_gl_getswapinterval(_THIS)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *gfdata = (SDL_VideoData *) _this->driverdata;

    /* Return default swap interval value */
    return gfdata->swapinterval;
#else
    SDL_SetError("GF: OpenGL ES support is not compiled in");
    return -1;
#endif /* SDL_VIDEO_OPENGL_ES */
}

void
qnxgf_gl_swapwindow(_THIS, SDL_Window * window)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *gfdata = (SDL_VideoData *) _this->driverdata;
    SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;

    /* Finish all drawings */
    glFinish();

    /* Swap buffers */
    eglSwapBuffers(gfdata->egldisplay, wdata->gles_surface);
#else
    SDL_SetError("GF: OpenGL ES support is not compiled in");
    return;
#endif /* SDL_VIDEO_OPENGL_ES */
}

void
qnxgf_gl_deletecontext(_THIS, SDL_GLContext context)
{
#if defined(SDL_VIDEO_OPENGL_ES)
    SDL_VideoData *gfdata = (SDL_VideoData *) _this->driverdata;
    EGLBoolean status;

    /* Check if OpenGL ES connection has been initialized */
    if (gfdata->egldisplay != EGL_NO_DISPLAY) {
        if (context != EGL_NO_CONTEXT) {
            status = eglDestroyContext(gfdata->egldisplay, context);
            if (status != EGL_TRUE) {
                /* Error during OpenGL ES context destroying */
                SDL_SetError("GF: OpenGL ES context destroy error");
                return;
            }
        }
    }

    return;
#else
    SDL_SetError("GF: OpenGL ES support is not compiled in");
    return;
#endif /* SDL_VIDEO_OPENGL_ES */
}

/*****************************************************************************/
/* SDL Event handling function                                               */
/*****************************************************************************/
void
qnxgf_pumpevents(_THIS)
{
}

/*****************************************************************************/
/* SDL screen saver related functions                                        */
/*****************************************************************************/
void
qnxgf_suspendscreensaver(_THIS)
{
    /* There is no screensaver in pure console, it may exist when running */
    /* GF under Photon, but I do not know, how to disable screensaver     */
}

/* vi: set ts=4 sw=4 expandtab: */