Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/videomode Add a new function - sort_modes() - to sor...



details:   https://anonhg.NetBSD.org/src/rev/d1b597da6bcc
branches:  trunk
changeset: 763979:d1b597da6bcc
user:      jdc <jdc%NetBSD.org@localhost>
date:      Sat Apr 09 18:22:31 2011 +0000

description:
Add a new function - sort_modes() - to sort video modes in an approximate
order of preference.

The preferred mode is placed first.  If there is no preferred mode, then
the first mode with highest resolution is placed first.  Other modes are
then sorted on difference from the first mode by refresh rate, aspect
ratio, then size.

diffstat:

 sys/dev/videomode/pickmode.c  |  109 +++++++++++++++++++++++++++++++++++++++++-
 sys/dev/videomode/videomode.h |    3 +-
 2 files changed, 109 insertions(+), 3 deletions(-)

diffs (143 lines):

diff -r bc3971e17892 -r d1b597da6bcc sys/dev/videomode/pickmode.c
--- a/sys/dev/videomode/pickmode.c      Sat Apr 09 18:18:28 2011 +0000
+++ b/sys/dev/videomode/pickmode.c      Sat Apr 09 18:22:31 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pickmode.c,v 1.2 2010/10/12 16:18:19 macallan Exp $ */
+/* $NetBSD: pickmode.c,v 1.3 2011/04/09 18:22:31 jdc Exp $ */
 
 /*-
  * Copyright (c) 2006 The NetBSD Foundation
@@ -29,7 +29,7 @@
  */ 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pickmode.c,v 1.2 2010/10/12 16:18:19 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pickmode.c,v 1.3 2011/04/09 18:22:31 jdc Exp $");
 
 #include <sys/param.h>
 #include <dev/videomode/videomode.h>
@@ -101,3 +101,108 @@
 
        return best;
 }
+
+static inline void
+swap_modes(struct videomode *left, struct videomode *right)
+{
+       struct videomode temp;
+
+       memcpy(&temp, left, sizeof(struct videomode));
+       memcpy(left, right, sizeof(struct videomode));
+       memcpy(right, &temp, sizeof(struct videomode));
+}
+
+/*
+ * Sort 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.
+ */
+#define        DIVIDE(x,y)     (((x) + ((y) / 2)) / (y))
+void
+sort_modes(struct videomode *modes, struct videomode **preferred, int nmodes)
+{
+       int aspect, refresh, hbest, vbest, abest, atemp, rbest, rtemp;
+       int i, j;
+       struct videomode *mtemp = NULL;
+
+       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)->dot_clock * 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;
+                               mtemp = &modes[i];
+                       } else if (modes[i].hdisplay == hbest &&
+                           modes[i].vdisplay > vbest) {
+                               vbest = modes[i].vdisplay;
+                               mtemp = &modes[i];
+                       }
+               }
+               aspect = mtemp->hdisplay * 100 / mtemp->vdisplay;
+               refresh = DIVIDE(DIVIDE(mtemp->dot_clock * 1000,
+                   mtemp->htotal), mtemp->vtotal);
+               if (mtemp != modes)
+                       swap_modes(mtemp, 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].dot_clock * 1000,
+                           modes[i].htotal), modes[i].vtotal));
+                       atemp = (modes[i].hdisplay * 100 / modes[i].vdisplay);
+                       if (rtemp < rbest) {
+                               rbest = rtemp;
+                               mtemp = &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;
+                                       mtemp = &modes[i];
+                               }
+                               if (atemp == abest ||
+                                   abs(abest - atemp) <= (abest / 8)) {
+                                       if (modes[i].hdisplay > hbest) {
+                                               hbest = modes[i].hdisplay;
+                                               mtemp = &modes[i];
+                                       }
+                                       if (modes[i].hdisplay == hbest &&
+                                           modes[i].vdisplay > vbest) {
+                                               vbest = modes[i].vdisplay;
+                                               mtemp = &modes[i];
+                                       }
+                               }
+                       }
+               }
+               if (mtemp != &modes[j])
+                       swap_modes(mtemp, &modes[j]);
+       }
+}
diff -r bc3971e17892 -r d1b597da6bcc sys/dev/videomode/videomode.h
--- a/sys/dev/videomode/videomode.h     Sat Apr 09 18:18:28 2011 +0000
+++ b/sys/dev/videomode/videomode.h     Sat Apr 09 18:22:31 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: videomode.h,v 1.2 2010/05/04 21:17:10 macallan Exp $   */
+/*     $NetBSD: videomode.h,v 1.3 2011/04/09 18:22:31 jdc Exp $        */
 
 /*
  * Copyright (c) 2001, 2002 Bang Jun-Young
@@ -68,5 +68,6 @@
 
 const struct videomode *pick_mode_by_dotclock(int, int, int);
 const struct videomode *pick_mode_by_ref(int, int, int);
+void sort_modes(struct videomode *, struct videomode **, int);
 
 #endif /* _DEV_VIDEOMODE_H */



Home | Main Index | Thread Index | Old Index