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