Home | History | Annotate | Download | only in main
      1 /**************************************************************************
      2  *
      3  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
      4  * Copyright 2009-2010 Chia-I Wu <olvaffe (at) gmail.com>
      5  * Copyright 2010 LunarG, Inc.
      6  * All Rights Reserved.
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a
      9  * copy of this software and associated documentation files (the
     10  * "Software"), to deal in the Software without restriction, including
     11  * without limitation the rights to use, copy, modify, merge, publish,
     12  * distribute, sub license, and/or sell copies of the Software, and to
     13  * permit persons to whom the Software is furnished to do so, subject to
     14  * the following conditions:
     15  *
     16  * The above copyright notice and this permission notice (including the
     17  * next paragraph) shall be included in all copies or substantial portions
     18  * of the Software.
     19  *
     20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     26  * DEALINGS IN THE SOFTWARE.
     27  *
     28  **************************************************************************/
     29 
     30 
     31 #include <assert.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 
     35 #include "egldisplay.h"
     36 #include "eglmode.h"
     37 #include "eglcurrent.h"
     38 #include "eglscreen.h"
     39 
     40 
     41 #ifdef EGL_MESA_screen_surface
     42 
     43 
     44 #define MIN2(A, B)  (((A) < (B)) ? (A) : (B))
     45 
     46 
     47 /**
     48  * Given an EGLModeMESA handle, return the corresponding _EGLMode object
     49  * or null if non-existant.
     50  */
     51 _EGLMode *
     52 _eglLookupMode(EGLModeMESA mode, _EGLDisplay *disp)
     53 {
     54    EGLint scrnum;
     55 
     56    if (!disp || !disp->Screens)
     57       return NULL;
     58 
     59    /* loop over all screens on the display */
     60    for (scrnum = 0; scrnum < disp->Screens->Size; scrnum++) {
     61       const _EGLScreen *scrn = disp->Screens->Elements[scrnum];
     62       EGLint idx;
     63 
     64       /*
     65        * the mode ids of a screen ranges from scrn->Handle to scrn->Handle +
     66        * scrn->NumModes
     67        */
     68       if (mode >= scrn->Handle &&
     69           mode < scrn->Handle + _EGL_SCREEN_MAX_MODES) {
     70          idx = mode - scrn->Handle;
     71 
     72          assert(idx < scrn->NumModes && scrn->Modes[idx].Handle == mode);
     73 
     74          return &scrn->Modes[idx];
     75       }
     76    }
     77 
     78    return NULL;
     79 }
     80 
     81 
     82 /**
     83  * Parse the attrib_list to fill in the fields of the given _eglMode
     84  * Return EGL_FALSE if any errors, EGL_TRUE otherwise.
     85  */
     86 static EGLBoolean
     87 _eglParseModeAttribs(_EGLMode *mode, const EGLint *attrib_list)
     88 {
     89    EGLint i;
     90 
     91    /* init all attribs to EGL_DONT_CARE */
     92    mode->Handle = EGL_DONT_CARE;
     93    mode->Width = EGL_DONT_CARE;
     94    mode->Height = EGL_DONT_CARE;
     95    mode->RefreshRate = EGL_DONT_CARE;
     96    mode->Optimal = EGL_DONT_CARE;
     97    mode->Interlaced = EGL_DONT_CARE;
     98    mode->Name = NULL;
     99 
    100    for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
    101       switch (attrib_list[i]) {
    102       case EGL_MODE_ID_MESA:
    103          mode->Handle = attrib_list[++i];
    104          if (mode->Handle <= 0) {
    105             _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(handle)");
    106             return EGL_FALSE;
    107          }
    108          break;
    109       case EGL_WIDTH:
    110          mode->Width = attrib_list[++i];
    111          if (mode->Width <= 0) {
    112             _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(width)");
    113             return EGL_FALSE;
    114          }
    115          break;
    116       case EGL_HEIGHT:
    117          mode->Height = attrib_list[++i];
    118          if (mode->Height <= 0) {
    119             _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(height)");
    120             return EGL_FALSE;
    121          }
    122          break;
    123       case EGL_REFRESH_RATE_MESA:
    124          mode->RefreshRate = attrib_list[++i];
    125          if (mode->RefreshRate <= 0) {
    126             _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(refresh rate)");
    127             return EGL_FALSE;
    128          }
    129          break;
    130       case EGL_INTERLACED_MESA:
    131          mode->Interlaced = attrib_list[++i];
    132          if (mode->Interlaced != EGL_TRUE && mode->Interlaced != EGL_FALSE) {
    133             _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(interlaced)");
    134             return EGL_FALSE;
    135          }
    136          break;
    137       case EGL_OPTIMAL_MESA:
    138          mode->Optimal = attrib_list[++i];
    139          if (mode->Optimal != EGL_TRUE && mode->Optimal != EGL_FALSE) {
    140             _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(optimal)");
    141             return EGL_FALSE;
    142          }
    143          break;
    144       default:
    145          _eglError(EGL_BAD_ATTRIBUTE, "eglChooseModeMESA");
    146          return EGL_FALSE;
    147       }
    148    }
    149    return EGL_TRUE;
    150 }
    151 
    152 
    153 /**
    154  * Determine if the candidate mode's attributes are at least as good
    155  * as the minimal mode's.
    156  * \return EGL_TRUE if qualifies, EGL_FALSE otherwise
    157  */
    158 static EGLBoolean
    159 _eglModeQualifies(const _EGLMode *c, const _EGLMode *min)
    160 {
    161    if (min->Handle != EGL_DONT_CARE && c->Handle != min->Handle)
    162       return EGL_FALSE;
    163    if (min->Width != EGL_DONT_CARE && c->Width < min->Width)
    164       return EGL_FALSE;
    165    if (min->Height != EGL_DONT_CARE && c->Height < min->Height)
    166       return EGL_FALSE;
    167    if (min->RefreshRate != EGL_DONT_CARE && c->RefreshRate < min->RefreshRate)
    168       return EGL_FALSE;
    169    if (min->Optimal != EGL_DONT_CARE && c->Optimal != min->Optimal)
    170       return EGL_FALSE;
    171    if (min->Interlaced != EGL_DONT_CARE && c->Interlaced != min->Interlaced)
    172       return EGL_FALSE;
    173 
    174    return EGL_TRUE;
    175 }
    176 
    177 
    178 /**
    179  * Return value of given mode attribute, or -1 if bad attrib.
    180  */
    181 static EGLint
    182 getModeAttrib(const _EGLMode *m, EGLint attrib)
    183 {
    184    switch (attrib) {
    185    case EGL_MODE_ID_MESA:
    186       return m->Handle;
    187    case EGL_WIDTH:
    188       return m->Width;
    189    case EGL_HEIGHT:
    190       return m->Height;
    191    case EGL_REFRESH_RATE_MESA:
    192       return m->RefreshRate;
    193    case EGL_OPTIMAL_MESA:
    194       return m->Optimal;
    195    case EGL_INTERLACED_MESA:
    196       return m->Interlaced;
    197    default:
    198       return -1;
    199    }
    200 }
    201 
    202 
    203 #define SMALLER 1
    204 #define LARGER  2
    205 
    206 struct sort_info {
    207    EGLint Attrib;
    208    EGLint Order; /* SMALLER or LARGER */
    209 };
    210 
    211 /* the order of these entries is the priority */
    212 static struct sort_info SortInfo[] = {
    213    { EGL_OPTIMAL_MESA, LARGER },
    214    { EGL_INTERLACED_MESA, SMALLER },
    215    { EGL_WIDTH, LARGER },
    216    { EGL_HEIGHT, LARGER },
    217    { EGL_REFRESH_RATE_MESA, LARGER },
    218    { EGL_MODE_ID_MESA, SMALLER },
    219    { 0, 0 }
    220 };
    221 
    222 
    223 /**
    224  * Compare modes 'a' and 'b' and return -1 if a belongs before b, or 1 if a
    225  * belongs after b, or 0 if they're equal.
    226  * Used by qsort().
    227  */
    228 static int
    229 _eglCompareModes(const void *a, const void *b)
    230 {
    231    const _EGLMode *aMode = *((const _EGLMode **) a);
    232    const _EGLMode *bMode = *((const _EGLMode **) b);
    233    EGLint i;
    234 
    235    for (i = 0; SortInfo[i].Attrib; i++) {
    236       const EGLint aVal = getModeAttrib(aMode, SortInfo[i].Attrib);
    237       const EGLint bVal = getModeAttrib(bMode, SortInfo[i].Attrib);
    238       if (aVal == bVal) {
    239          /* a tie */
    240          continue;
    241       }
    242       else if (SortInfo[i].Order == SMALLER) {
    243          return (aVal < bVal) ? -1 : 1;
    244       }
    245       else if (SortInfo[i].Order == LARGER) {
    246          return (aVal > bVal) ? -1 : 1;
    247       }
    248    }
    249 
    250    /* all attributes identical */
    251    return 0;
    252 }
    253 
    254 
    255 /**
    256  * Search for EGLModes which match the given attribute list.
    257  * Called via eglChooseModeMESA API function.
    258  */
    259 EGLBoolean
    260 _eglChooseModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
    261                    const EGLint *attrib_list, EGLModeMESA *modes,
    262                    EGLint modes_size, EGLint *num_modes)
    263 {
    264    _EGLMode **modeList, min;
    265    EGLint i, count;
    266 
    267    if (!_eglParseModeAttribs(&min, attrib_list)) {
    268       /* error code will have been recorded */
    269       return EGL_FALSE;
    270    }
    271 
    272    /* allocate array of mode pointers */
    273    modeList = (_EGLMode **) malloc(modes_size * sizeof(_EGLMode *));
    274    if (!modeList) {
    275       _eglError(EGL_BAD_MODE_MESA, "eglChooseModeMESA(out of memory)");
    276       return EGL_FALSE;
    277    }
    278 
    279    /* make array of pointers to qualifying modes */
    280    for (i = count = 0; i < scrn->NumModes && count < modes_size; i++) {
    281       if (_eglModeQualifies(scrn->Modes + i, &min)) {
    282          modeList[count++] = scrn->Modes + i;
    283       }
    284    }
    285 
    286    /* sort array of pointers */
    287    qsort(modeList, count, sizeof(_EGLMode *), _eglCompareModes);
    288 
    289    /* copy mode handles to output array */
    290    for (i = 0; i < count; i++) {
    291       modes[i] = modeList[i]->Handle;
    292    }
    293 
    294    free(modeList);
    295 
    296    *num_modes = count;
    297 
    298    return EGL_TRUE;
    299 }
    300 
    301 
    302 
    303 /**
    304  * Return all possible modes for the given screen.  No sorting of results.
    305  * Called via eglGetModesMESA() API function.
    306  */
    307 EGLBoolean
    308 _eglGetModesMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
    309                  EGLModeMESA *modes, EGLint modes_size, EGLint *num_modes)
    310 {
    311    if (modes) {
    312       EGLint i;
    313       *num_modes = MIN2(scrn->NumModes, modes_size);
    314       for (i = 0; i < *num_modes; i++) {
    315          modes[i] = scrn->Modes[i].Handle;
    316       }
    317    }
    318    else {
    319       /* just return total number of supported modes */
    320       *num_modes = scrn->NumModes;
    321    }
    322 
    323    return EGL_TRUE;
    324 }
    325 
    326 
    327 /**
    328  * Query an attribute of a mode.
    329  */
    330 EGLBoolean
    331 _eglGetModeAttribMESA(_EGLDriver *drv, _EGLDisplay *dpy,
    332                       _EGLMode *m, EGLint attribute, EGLint *value)
    333 {
    334    EGLint v;
    335 
    336    v = getModeAttrib(m, attribute);
    337    if (v < 0) {
    338       _eglError(EGL_BAD_ATTRIBUTE, "eglGetModeAttribMESA");
    339       return EGL_FALSE;
    340    }
    341    *value = v;
    342    return EGL_TRUE;
    343 }
    344 
    345 
    346 /**
    347  * Return human-readable string for given mode.
    348  * This is the default function called by eglQueryModeStringMESA().
    349  */
    350 const char *
    351 _eglQueryModeStringMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLMode *m)
    352 {
    353    return m->Name;
    354 }
    355 
    356 
    357 #endif /* EGL_MESA_screen_surface */
    358