summaryrefslogtreecommitdiffstats
path: root/src/egl/main/eglmode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl/main/eglmode.c')
-rw-r--r--src/egl/main/eglmode.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/src/egl/main/eglmode.c b/src/egl/main/eglmode.c
new file mode 100644
index 00000000000..786432234bb
--- /dev/null
+++ b/src/egl/main/eglmode.c
@@ -0,0 +1,431 @@
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "egldisplay.h"
+#include "egldriver.h"
+#include "eglmode.h"
+#include "eglglobals.h"
+#include "eglscreen.h"
+
+
+#define MIN2(A, B) (((A) < (B)) ? (A) : (B))
+
+
+static char *
+my_strdup(const char *s)
+{
+ if (s) {
+ int l = strlen(s);
+ char *s2 = malloc(l + 1);
+ if (s2)
+ strcpy(s2, s);
+ return s2;
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+/**
+ * Given an EGLModeMESA handle, return the corresponding _EGLMode object
+ * or null if non-existant.
+ */
+_EGLMode *
+_eglLookupMode(EGLDisplay dpy, EGLModeMESA mode)
+{
+ const _EGLDisplay *disp = _eglLookupDisplay(dpy);
+ EGLint scrnum;
+
+ /* loop over all screens on the display */
+ for (scrnum = 0; scrnum < disp->NumScreens; scrnum++) {
+ const _EGLScreen *scrn = disp->Screens[scrnum];
+ EGLint i;
+ /* search list of modes for handle */
+ for (i = 0; i < scrn->NumModes; i++) {
+ if (scrn->Modes[i].Handle == mode) {
+ return scrn->Modes + i;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Add a new mode with the given attributes (width, height, depth, refreshRate)
+ * to the given screen.
+ * Assign a new mode ID/handle to the mode as well.
+ * \return pointer to the new _EGLMode
+ */
+_EGLMode *
+_eglAddNewMode(_EGLScreen *screen, EGLint width, EGLint height,
+ EGLint refreshRate, const char *name)
+{
+ EGLint n;
+ _EGLMode *newModes;
+
+ assert(screen);
+ assert(width > 0);
+ assert(height > 0);
+ assert(refreshRate > 0);
+
+ n = screen->NumModes;
+ newModes = (_EGLMode *) realloc(screen->Modes, (n+1) * sizeof(_EGLMode));
+ if (newModes) {
+ screen->Modes = newModes;
+ screen->Modes[n].Handle = n + 1;
+ screen->Modes[n].Width = width;
+ screen->Modes[n].Height = height;
+ screen->Modes[n].RefreshRate = refreshRate;
+ screen->Modes[n].Optimal = EGL_FALSE;
+ screen->Modes[n].Interlaced = EGL_FALSE;
+ screen->Modes[n].Name = my_strdup(name);
+ screen->NumModes++;
+ return screen->Modes + n;
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+
+/**
+ * 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
+_eglChooseModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
+ const EGLint *attrib_list, EGLModeMESA *modes,
+ EGLint modes_size, EGLint *num_modes)
+{
+ const _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
+ _EGLMode **modeList, min;
+ EGLint i, count;
+
+ if (!scrn) {
+ _eglError(EGL_BAD_SCREEN_MESA, "eglChooseModeMESA");
+ return EGL_FALSE;
+ }
+
+ if (!_eglParseModeAttribs(&min, attrib_list)) {
+ /* error code will have been recorded */
+ return EGL_FALSE;
+ }
+
+ /* allocate array of mode pointers */
+ modeList = (_EGLMode **) malloc(modes_size * sizeof(_EGLMode *));
+ if (!modeList) {
+ _eglError(EGL_BAD_MODE_MESA, "eglChooseModeMESA(out of memory)");
+ return EGL_FALSE;
+ }
+
+ /* make array of pointers to qualifying modes */
+ for (i = count = 0; i < scrn->NumModes && count < modes_size; i++) {
+ if (_eglModeQualifies(scrn->Modes + i, &min)) {
+ modeList[count++] = scrn->Modes + i;
+ }
+ }
+
+ /* 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 all possible modes for the given screen. No sorting of results.
+ * Called via eglGetModesMESA() API function.
+ */
+EGLBoolean
+_eglGetModesMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
+ EGLModeMESA *modes, EGLint modes_size, EGLint *num_modes)
+{
+ _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
+
+ if (!scrn) {
+ _eglError(EGL_BAD_SCREEN_MESA, "eglGetModesMESA");
+ return EGL_FALSE;
+ }
+
+ if (modes) {
+ EGLint i;
+ *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;
+}
+
+
+/**
+ * Query an attribute of a mode.
+ */
+EGLBoolean
+_eglGetModeAttribMESA(_EGLDriver *drv, EGLDisplay dpy,
+ EGLModeMESA mode, EGLint attribute, EGLint *value)
+{
+ _EGLMode *m = _eglLookupMode(dpy, mode);
+ EGLint v;
+
+ if (!m) {
+ _eglError(EGL_BAD_MODE_MESA, "eglGetModeAttribMESA");
+ return EGL_FALSE;
+ }
+
+ v = getModeAttrib(m, attribute);
+ if (v < 0) {
+ _eglError(EGL_BAD_ATTRIBUTE, "eglGetModeAttribMESA");
+ return EGL_FALSE;
+ }
+ *value = v;
+ return EGL_TRUE;
+}
+
+
+/**
+ * Return human-readable string for given mode.
+ * This is the default function called by eglQueryModeStringMESA().
+ */
+const char *
+_eglQueryModeStringMESA(_EGLDriver *drv, EGLDisplay dpy, EGLModeMESA mode)
+{
+ _EGLMode *m = _eglLookupMode(dpy, mode);
+ if (!m) {
+ _eglError(EGL_BAD_MODE_MESA, "eglQueryModeStringMESA");
+ return NULL;
+ }
+ 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