/**************************************************************************** * video/videomode/videomode_sort.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define DIVIDE(x, y) (((x) + ((y) / 2)) / (y)) /**************************************************************************** * Private Functions ****************************************************************************/ static inline void videomode_swap(FAR struct videomode_s *left, FAR struct videomode_s *right) { struct 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: sort_videomodes * * 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 sort_videomodes(FAR struct videomode_s *modes, FAR struct videomode_s **preferred, unsigned int nmodes) { FAR struct 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) { videomode_swap(*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) { videomode_swap(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]) { videomode_swap(tmpmode, &modes[j]); } } }