lots of updates, mode sorting, etc
This commit is contained in:
parent
6002d2ff4e
commit
ad6f8eba00
|
@ -1,3 +1,4 @@
|
||||||
|
#include <stdio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -15,10 +16,16 @@
|
||||||
static char *
|
static char *
|
||||||
my_strdup(const char *s)
|
my_strdup(const char *s)
|
||||||
{
|
{
|
||||||
int l = strlen(s);
|
if (s) {
|
||||||
char *s2 = malloc(l + 1);
|
int l = strlen(s);
|
||||||
strcpy(s2, s);
|
char *s2 = malloc(l + 1);
|
||||||
return s2;
|
if (s2)
|
||||||
|
strcpy(s2, s);
|
||||||
|
return s2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,8 +62,8 @@ _eglLookupMode(EGLDisplay dpy, EGLModeMESA mode)
|
||||||
* \return pointer to the new _EGLMode
|
* \return pointer to the new _EGLMode
|
||||||
*/
|
*/
|
||||||
_EGLMode *
|
_EGLMode *
|
||||||
_eglAddMode(_EGLScreen *screen, EGLint width, EGLint height,
|
_eglAddNewMode(_EGLScreen *screen, EGLint width, EGLint height,
|
||||||
EGLint refreshRate, const char *name)
|
EGLint refreshRate, const char *name)
|
||||||
{
|
{
|
||||||
EGLint n;
|
EGLint n;
|
||||||
_EGLMode *newModes;
|
_EGLMode *newModes;
|
||||||
|
@ -74,7 +81,8 @@ _eglAddMode(_EGLScreen *screen, EGLint width, EGLint height,
|
||||||
screen->Modes[n].Width = width;
|
screen->Modes[n].Width = width;
|
||||||
screen->Modes[n].Height = height;
|
screen->Modes[n].Height = height;
|
||||||
screen->Modes[n].RefreshRate = refreshRate;
|
screen->Modes[n].RefreshRate = refreshRate;
|
||||||
screen->Modes[n].Stereo = EGL_FALSE;
|
screen->Modes[n].Optimal = EGL_FALSE;
|
||||||
|
screen->Modes[n].Interlaced = EGL_FALSE;
|
||||||
screen->Modes[n].Name = my_strdup(name);
|
screen->Modes[n].Name = my_strdup(name);
|
||||||
screen->NumModes++;
|
screen->NumModes++;
|
||||||
return screen->Modes + n;
|
return screen->Modes + n;
|
||||||
|
@ -87,62 +95,257 @@ _eglAddMode(_EGLScreen *screen, EGLint width, EGLint height,
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search for the EGLMode that best matches the given attribute list.
|
* Parse the attrib_list to fill in the fields of the given _eglMode
|
||||||
|
* Return EGL_FALSE if any errors, EGL_TRUE otherwise.
|
||||||
|
*/
|
||||||
|
static EGLBoolean
|
||||||
|
_eglParseModeAttribs(_EGLMode *mode, const EGLint *attrib_list)
|
||||||
|
{
|
||||||
|
EGLint i;
|
||||||
|
|
||||||
|
/* init all attribs to EGL_DONT_CARE */
|
||||||
|
mode->Handle = EGL_DONT_CARE;
|
||||||
|
mode->Width = EGL_DONT_CARE;
|
||||||
|
mode->Height = EGL_DONT_CARE;
|
||||||
|
mode->RefreshRate = EGL_DONT_CARE;
|
||||||
|
mode->Optimal = EGL_DONT_CARE;
|
||||||
|
mode->Interlaced = EGL_DONT_CARE;
|
||||||
|
mode->Name = NULL;
|
||||||
|
|
||||||
|
for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
|
||||||
|
switch (attrib_list[i]) {
|
||||||
|
case EGL_MODE_ID_MESA:
|
||||||
|
mode->Handle = attrib_list[++i];
|
||||||
|
if (mode->Handle <= 0) {
|
||||||
|
_eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(handle)");
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EGL_WIDTH:
|
||||||
|
mode->Width = attrib_list[++i];
|
||||||
|
if (mode->Width <= 0) {
|
||||||
|
_eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(width)");
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EGL_HEIGHT:
|
||||||
|
mode->Height = attrib_list[++i];
|
||||||
|
if (mode->Height <= 0) {
|
||||||
|
_eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(height)");
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EGL_REFRESH_RATE_MESA:
|
||||||
|
mode->RefreshRate = attrib_list[++i];
|
||||||
|
if (mode->RefreshRate <= 0) {
|
||||||
|
_eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(refresh rate)");
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EGL_INTERLACED_MESA:
|
||||||
|
mode->Interlaced = attrib_list[++i];
|
||||||
|
if (mode->Interlaced != EGL_TRUE && mode->Interlaced != EGL_FALSE) {
|
||||||
|
_eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(interlaced)");
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EGL_OPTIMAL_MESA:
|
||||||
|
mode->Optimal = attrib_list[++i];
|
||||||
|
if (mode->Optimal != EGL_TRUE && mode->Optimal != EGL_FALSE) {
|
||||||
|
_eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(optimal)");
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_eglError(EGL_BAD_ATTRIBUTE, "eglChooseModeMESA");
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EGL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the candidate mode's attributes are at least as good
|
||||||
|
* as the minimal mode's.
|
||||||
|
* \return EGL_TRUE if qualifies, EGL_FALSE otherwise
|
||||||
|
*/
|
||||||
|
static EGLBoolean
|
||||||
|
_eglModeQualifies(const _EGLMode *c, const _EGLMode *min)
|
||||||
|
{
|
||||||
|
if (min->Handle != EGL_DONT_CARE && c->Handle != min->Handle)
|
||||||
|
return EGL_FALSE;
|
||||||
|
if (min->Width != EGL_DONT_CARE && c->Width < min->Width)
|
||||||
|
return EGL_FALSE;
|
||||||
|
if (min->Height != EGL_DONT_CARE && c->Height < min->Height)
|
||||||
|
return EGL_FALSE;
|
||||||
|
if (min->RefreshRate != EGL_DONT_CARE && c->RefreshRate < min->RefreshRate)
|
||||||
|
return EGL_FALSE;
|
||||||
|
if (min->Optimal != EGL_DONT_CARE && c->Optimal != min->Optimal)
|
||||||
|
return EGL_FALSE;
|
||||||
|
if (min->Interlaced != EGL_DONT_CARE && c->Interlaced != min->Interlaced)
|
||||||
|
return EGL_FALSE;
|
||||||
|
|
||||||
|
return EGL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return value of given mode attribute, or -1 if bad attrib.
|
||||||
|
*/
|
||||||
|
static EGLint
|
||||||
|
getModeAttrib(const _EGLMode *m, EGLint attrib)
|
||||||
|
{
|
||||||
|
switch (attrib) {
|
||||||
|
case EGL_MODE_ID_MESA:
|
||||||
|
return m->Handle;
|
||||||
|
case EGL_WIDTH:
|
||||||
|
return m->Width;
|
||||||
|
case EGL_HEIGHT:
|
||||||
|
return m->Height;
|
||||||
|
case EGL_REFRESH_RATE_MESA:
|
||||||
|
return m->RefreshRate;
|
||||||
|
case EGL_OPTIMAL_MESA:
|
||||||
|
return m->Optimal;
|
||||||
|
case EGL_INTERLACED_MESA:
|
||||||
|
return m->Interlaced;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SMALLER 1
|
||||||
|
#define LARGER 2
|
||||||
|
|
||||||
|
struct sort_info {
|
||||||
|
EGLint Attrib;
|
||||||
|
EGLint Order; /* SMALLER or LARGER */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* the order of these entries is the priority */
|
||||||
|
static struct sort_info SortInfo[] = {
|
||||||
|
{ EGL_OPTIMAL_MESA, LARGER },
|
||||||
|
{ EGL_INTERLACED_MESA, SMALLER },
|
||||||
|
{ EGL_WIDTH, LARGER },
|
||||||
|
{ EGL_HEIGHT, LARGER },
|
||||||
|
{ EGL_REFRESH_RATE_MESA, LARGER },
|
||||||
|
{ EGL_MODE_ID_MESA, SMALLER },
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare modes 'a' and 'b' and return -1 if a belongs before b, or 1 if a
|
||||||
|
* belongs after b, or 0 if they're equal.
|
||||||
|
* Used by qsort().
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
_eglCompareModes(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const _EGLMode *aMode = *((const _EGLMode **) a);
|
||||||
|
const _EGLMode *bMode = *((const _EGLMode **) b);
|
||||||
|
EGLint i;
|
||||||
|
|
||||||
|
for (i = 0; SortInfo[i].Attrib; i++) {
|
||||||
|
const EGLint aVal = getModeAttrib(aMode, SortInfo[i].Attrib);
|
||||||
|
const EGLint bVal = getModeAttrib(bMode, SortInfo[i].Attrib);
|
||||||
|
if (aVal == bVal) {
|
||||||
|
/* a tie */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (SortInfo[i].Order == SMALLER) {
|
||||||
|
return (aVal < bVal) ? -1 : 1;
|
||||||
|
}
|
||||||
|
else if (SortInfo[i].Order == LARGER) {
|
||||||
|
return (aVal > bVal) ? -1 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* all attributes identical */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for EGLModes which match the given attribute list.
|
||||||
|
* Called via eglChooseModeMESA API function.
|
||||||
*/
|
*/
|
||||||
EGLBoolean
|
EGLBoolean
|
||||||
_eglChooseModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
|
_eglChooseModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
|
||||||
const EGLint *attrib_list, EGLModeMESA *modes,
|
const EGLint *attrib_list, EGLModeMESA *modes,
|
||||||
EGLint modes_size, EGLint *num_modes)
|
EGLint modes_size, EGLint *num_modes)
|
||||||
{
|
{
|
||||||
EGLint i;
|
const _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
|
||||||
|
_EGLMode **modeList, min;
|
||||||
|
EGLint i, count;
|
||||||
|
|
||||||
/* XXX incomplete */
|
if (!scrn) {
|
||||||
|
_eglError(EGL_BAD_SCREEN_MESA, "eglChooseModeMESA");
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
|
if (!_eglParseModeAttribs(&min, attrib_list)) {
|
||||||
switch (attrib_list[i]) {
|
/* error code will have been recorded */
|
||||||
case EGL_WIDTH:
|
return EGL_FALSE;
|
||||||
i++;
|
}
|
||||||
break;
|
|
||||||
case EGL_HEIGHT:
|
/* allocate array of mode pointers */
|
||||||
i++;
|
modeList = (_EGLMode **) malloc(modes_size * sizeof(_EGLMode *));
|
||||||
break;
|
if (!modeList) {
|
||||||
case EGL_REFRESH_RATE_MESA:
|
_eglError(EGL_BAD_MODE_MESA, "eglChooseModeMESA(out of memory)");
|
||||||
i++;
|
return EGL_FALSE;
|
||||||
break;
|
}
|
||||||
#if 0
|
|
||||||
case EGL_STEREO_MESA:
|
/* make array of pointers to qualifying modes */
|
||||||
i++;
|
for (i = count = 0; i < scrn->NumModes && count < modes_size; i++) {
|
||||||
break;
|
if (_eglModeQualifies(scrn->Modes + i, &min)) {
|
||||||
#endif
|
modeList[count++] = scrn->Modes + i;
|
||||||
default:
|
|
||||||
_eglError(EGL_BAD_ATTRIBUTE, "eglChooseMode");
|
|
||||||
return EGL_FALSE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sort array of pointers */
|
||||||
|
qsort(modeList, count, sizeof(_EGLMode *), _eglCompareModes);
|
||||||
|
|
||||||
|
/* copy mode handles to output array */
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
modes[i] = modeList[i]->Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(modeList);
|
||||||
|
|
||||||
|
*num_modes = count;
|
||||||
|
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all possible modes for the given screen
|
* Return all possible modes for the given screen. No sorting of results.
|
||||||
|
* Called via eglGetModesMESA() API function.
|
||||||
*/
|
*/
|
||||||
EGLBoolean
|
EGLBoolean
|
||||||
_eglGetModesMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
|
_eglGetModesMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
|
||||||
EGLModeMESA *modes, EGLint modes_size, EGLint *num_modes)
|
EGLModeMESA *modes, EGLint modes_size, EGLint *num_modes)
|
||||||
{
|
{
|
||||||
_EGLScreen *scrn = _eglLookupScreen(dpy, screen);
|
_EGLScreen *scrn = _eglLookupScreen(dpy, screen);
|
||||||
EGLint i;
|
|
||||||
|
|
||||||
if (!scrn) {
|
if (!scrn) {
|
||||||
_eglError(EGL_BAD_SCREEN_MESA, "eglGetModes");
|
_eglError(EGL_BAD_SCREEN_MESA, "eglGetModesMESA");
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
*num_modes = MIN2(modes_size, scrn->NumModes);
|
if (modes) {
|
||||||
for (i = 0; i < *num_modes; i++) {
|
EGLint i;
|
||||||
modes[i] = scrn->Modes[i].Handle;
|
*num_modes = MIN2(scrn->NumModes, modes_size);
|
||||||
|
for (i = 0; i < *num_modes; i++) {
|
||||||
|
modes[i] = scrn->Modes[i].Handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* just return total number of supported modes */
|
||||||
|
*num_modes = scrn->NumModes;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
|
@ -157,43 +360,72 @@ _eglGetModeAttribMESA(_EGLDriver *drv, EGLDisplay dpy,
|
||||||
EGLModeMESA mode, EGLint attribute, EGLint *value)
|
EGLModeMESA mode, EGLint attribute, EGLint *value)
|
||||||
{
|
{
|
||||||
_EGLMode *m = _eglLookupMode(dpy, mode);
|
_EGLMode *m = _eglLookupMode(dpy, mode);
|
||||||
|
EGLint v;
|
||||||
|
|
||||||
switch (attribute) {
|
if (!m) {
|
||||||
case EGL_MODE_ID_MESA:
|
_eglError(EGL_BAD_MODE_MESA, "eglGetModeAttribMESA");
|
||||||
*value = m->Handle;
|
|
||||||
break;
|
|
||||||
case EGL_WIDTH:
|
|
||||||
*value = m->Width;
|
|
||||||
break;
|
|
||||||
case EGL_HEIGHT:
|
|
||||||
*value = m->Height;
|
|
||||||
break;
|
|
||||||
#if 0
|
|
||||||
case EGL_DEPTH_MESA:
|
|
||||||
*value = m->Depth;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case EGL_REFRESH_RATE_MESA:
|
|
||||||
*value = m->RefreshRate;
|
|
||||||
break;
|
|
||||||
#if 0
|
|
||||||
case EGL_STEREO_MESA:
|
|
||||||
*value = m->Stereo;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
_eglError(EGL_BAD_ATTRIBUTE, "eglGetModeAttrib");
|
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v = getModeAttrib(m, attribute);
|
||||||
|
if (v < 0) {
|
||||||
|
_eglError(EGL_BAD_ATTRIBUTE, "eglGetModeAttribMESA");
|
||||||
|
return EGL_FALSE;
|
||||||
|
}
|
||||||
|
*value = v;
|
||||||
return EGL_TRUE;
|
return EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return human-readable string for given mode.
|
||||||
|
* This is the default function called by eglQueryModeStringMESA().
|
||||||
|
*/
|
||||||
const char *
|
const char *
|
||||||
_eglQueryModeStringMESA(_EGLDriver *drv, EGLDisplay dpy, EGLModeMESA mode)
|
_eglQueryModeStringMESA(_EGLDriver *drv, EGLDisplay dpy, EGLModeMESA mode)
|
||||||
{
|
{
|
||||||
_EGLMode *m = _eglLookupMode(dpy, mode);
|
_EGLMode *m = _eglLookupMode(dpy, mode);
|
||||||
|
if (!m) {
|
||||||
|
_eglError(EGL_BAD_MODE_MESA, "eglQueryModeStringMESA");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return m->Name;
|
return m->Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int
|
||||||
|
_eglRand(int max)
|
||||||
|
{
|
||||||
|
return rand() % max;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_eglTestModeModule(void)
|
||||||
|
{
|
||||||
|
EGLint count = 30;
|
||||||
|
_EGLMode *modes = (_EGLMode *) malloc(count * sizeof(_EGLMode));
|
||||||
|
_EGLMode **modeList = (_EGLMode **) malloc(count * sizeof(_EGLMode*));
|
||||||
|
EGLint i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
modes[i].Handle = _eglRand(20);
|
||||||
|
modes[i].Width = 512 + 256 * _eglRand(2);
|
||||||
|
modes[i].Height = 512 + 256 * _eglRand(2);
|
||||||
|
modes[i].RefreshRate = 50 + 5 * _eglRand(3);
|
||||||
|
modes[i].Interlaced = _eglRand(2);
|
||||||
|
modes[i].Optimal = _eglRand(4) == 0;
|
||||||
|
modeList[i] = modes + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort array of pointers */
|
||||||
|
qsort(modeList, count, sizeof(_EGLMode *), compareModes);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
_EGLMode *m = modeList[i];
|
||||||
|
printf("%2d: %3d %4d x %4d @ %3d opt %d int %d\n", i,
|
||||||
|
m->Handle, m->Width, m->Height, m->RefreshRate,
|
||||||
|
m->Optimal, m->Interlaced);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -12,7 +12,8 @@ struct _egl_mode
|
||||||
EGLModeMESA Handle; /* the public/opaque handle which names this mode */
|
EGLModeMESA Handle; /* the public/opaque handle which names this mode */
|
||||||
EGLint Width, Height; /* size in pixels */
|
EGLint Width, Height; /* size in pixels */
|
||||||
EGLint RefreshRate; /* rate * 1000.0 */
|
EGLint RefreshRate; /* rate * 1000.0 */
|
||||||
EGLBoolean Stereo;
|
EGLint Optimal;
|
||||||
|
EGLint Interlaced;
|
||||||
const char *Name;
|
const char *Name;
|
||||||
|
|
||||||
/* Other possible attributes */
|
/* Other possible attributes */
|
||||||
|
@ -26,8 +27,8 @@ _eglLookupMode(EGLDisplay dpy, EGLModeMESA mode);
|
||||||
|
|
||||||
|
|
||||||
extern _EGLMode *
|
extern _EGLMode *
|
||||||
_eglAddMode(_EGLScreen *screen, EGLint width, EGLint height,
|
_eglAddNewMode(_EGLScreen *screen, EGLint width, EGLint height,
|
||||||
EGLint refreshRate, const char *name);
|
EGLint refreshRate, const char *name);
|
||||||
|
|
||||||
|
|
||||||
extern EGLBoolean
|
extern EGLBoolean
|
||||||
|
|
Loading…
Reference in New Issue