diff --git a/include/nuttx/lcd/edid.h b/include/nuttx/lcd/edid.h index 44d407a5b9..8ceb3fd0e8 100644 --- a/include/nuttx/lcd/edid.h +++ b/include/nuttx/lcd/edid.h @@ -601,10 +601,13 @@ int edid_parse(FAR const uint8_t *data, FAR struct edid_info_s *edid); * Name: edid_sort_modes * * Description: - * Sort video modes by refresh rate, aspect ratio (*), then resolution. + * Sort video modes by refresh rate, aspect ratio, then resolution. * Preferred mode or largest mode is first in the list and other modes * are sorted on closest match to that mode. * + * Note that the aspect ratio calculation treats "close" aspect ratios + * (within 12.5%) as the same for this purpose. + * * Input Parameters: * modes - A reference to the first entry in a list of video modes * preferred - A pointer to the pointer to the preferred mode in the list diff --git a/video/edid/Make.defs b/video/edid/Make.defs index 18f98e2336..3c8b4a52e9 100644 --- a/video/edid/Make.defs +++ b/video/edid/Make.defs @@ -38,7 +38,7 @@ ifeq ($(CONFIG_VIDEO_EDID),y) # Files required for EDID support ASRCS += -CSRCS += edid_parse.c edid_videomode.c # edid_sort.c +CSRCS += edid_parse.c edid_videomode.c edid_sort.c # Include EDID build support diff --git a/video/edid/edid_parse.c b/video/edid/edid_parse.c index a4515c15fb..5492f05df5 100644 --- a/video/edid/edid_parse.c +++ b/video/edid/edid_parse.c @@ -1,7 +1,7 @@ /**************************************************************************** * video/edid/edid_parse.c * - * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Copyright (C) 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Derives from logic in FreeBSD which has an equivalent 3-clause BSD @@ -181,7 +181,7 @@ static bool edid_std_timing(FAR const uint8_t *stdtim, } else { -#if 0 /* Not implemented */ +#if 0 /* Not implemented. See FreeBSD sys/dev/videomode/vesagtf.c */ /* Failing that, calculate it using gtf * * Hmm. I'm not using alternate GTF timings, which diff --git a/video/edid/edid_sort.c b/video/edid/edid_sort.c new file mode 100644 index 0000000000..7ea5965128 --- /dev/null +++ b/video/edid/edid_sort.c @@ -0,0 +1,226 @@ +/**************************************************************************** + * video/edid/edid_sort.c + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Derives from logic in FreeBSD which has an compatible 2-clause BSD + * license: + * + * Copyright (c) 2006 The NetBSD Foundation. All rights reserved. + * Author: Michael Lorenz + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE NETBSD FOUNDATION BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DIVIDE(x, y) (((x) + ((y) / 2)) / (y)) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline void swap_modes(FAR struct edid_videomode_s *left, + FAR struct edid_videomode_s *right) +{ + struct edid_videomode_s temp; + + temp = *left; + *left = *right; + *right = temp; +} + +static inline int _abs(int a) +{ + if (a < 0) + { + return -a; + } + else + { + return a; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: edid_sort_modes + * + * Description: + * Sort video modes by refresh rate, aspect ratio, then resolution. + * Preferred mode or largest mode is first in the list and other modes + * are sorted on closest match to that mode. + * + * Note that the aspect ratio calculation treats "close" aspect ratios + * (within 12.5%) as the same for this purpose. + * + * Input Parameters: + * modes - A reference to the first entry in a list of video modes + * preferred - A pointer to the pointer to the preferred mode in the list + * nmodes - The number of modes in the list + * + * Returned Value: + * None + * + ****************************************************************************/ + +void edid_sort_modes(FAR struct edid_videomode_s *modes, + FAR struct edid_videomode_s **preferred, unsigned int nmodes) +{ + FAR struct edid_videomode_s *tmpmode = NULL; + int aspect; + int refresh; + int hbest; + int vbest; + int abest; + int atemp; + int rbest; + int rtemp; + int i; + int j; + + if (nmodes < 2) + { + return; + } + + if (*preferred != NULL) + { + /* Put the preferred mode first in the list */ + + aspect = (*preferred)->hdisplay * 100 / (*preferred)->vdisplay; + refresh = DIVIDE(DIVIDE((*preferred)->dotclock * 1000, + (*preferred)->htotal), (*preferred)->vtotal); + if (*preferred != modes) + { + swap_modes(*preferred, modes); + *preferred = modes; + } + } + else + { + /* Find the largest horizontal and vertical mode and put that + * first in the list. Preferred refresh rate is taken from + * the first mode of this size. + */ + + hbest = 0; + vbest = 0; + + for (i = 0; i < nmodes; i++) + { + if (modes[i].hdisplay > hbest) + { + hbest = modes[i].hdisplay; + vbest = modes[i].vdisplay; + tmpmode = &modes[i]; + } + else if (modes[i].hdisplay == hbest && modes[i].vdisplay > vbest) + { + vbest = modes[i].vdisplay; + tmpmode = &modes[i]; + } + } + + aspect = tmpmode->hdisplay * 100 / tmpmode->vdisplay; + refresh = DIVIDE(DIVIDE(tmpmode->dotclock * 1000, + tmpmode->htotal), tmpmode->vtotal); + if (tmpmode != modes) + { + swap_modes(tmpmode, modes); + } + } + + /* Sort other modes by refresh rate, aspect ratio, then resolution */ + + for (j = 1; j < nmodes - 1; j++) + { + rbest = 1000; + abest = 1000; + hbest = 0; + vbest = 0; + + for (i = j; i < nmodes; i++) + { + rtemp = _abs(refresh - + DIVIDE(DIVIDE(modes[i].dotclock * 1000, + modes[i].htotal), modes[i].vtotal)); + atemp = (modes[i].hdisplay * 100 / modes[i].vdisplay); + if (rtemp < rbest) + { + rbest = rtemp; + tmpmode = &modes[i]; + } + + if (rtemp == rbest) + { + /* Treat "close" aspect ratios as identical */ + + if (_abs(abest - atemp) > (abest / 8) && + _abs(aspect - atemp) < _abs(aspect - abest)) + { + abest = atemp; + tmpmode = &modes[i]; + } + + if (atemp == abest || _abs(abest - atemp) <= (abest / 8)) + { + if (modes[i].hdisplay > hbest) + { + hbest = modes[i].hdisplay; + tmpmode = &modes[i]; + } + + if (modes[i].hdisplay == hbest && modes[i].vdisplay > vbest) + { + vbest = modes[i].vdisplay; + tmpmode = &modes[i]; + } + } + } + } + + if (tmpmode != &modes[j]) + { + swap_modes(tmpmode, &modes[j]); + } + } +} diff --git a/video/edid/edid_videomode.c b/video/edid/edid_videomode.c index 9bd7fcbd3e..15f87ff2f1 100644 --- a/video/edid/edid_videomode.c +++ b/video/edid/edid_videomode.c @@ -1,7 +1,7 @@ /**************************************************************************** * video/edid/edid_parse.c * - * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Copyright (C) 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Derives from logic in FreeBSD which has an equivalent 3-clause BSD