mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
video: one place decides which mode a size and rate name
Mutter, KWin and wlroots each carried their own copy of the same two decisions - the listed mode a requested size and rate mean, and the order a resolution list is shown in. gfx/common/video_mode_select.c holds them once and all three call it, reading their own mode structures through a callback rather than copying them. The rules are the ones Mutter already applied and the two Wayland backends lacked: a rate further off than half a hertz is not the mode the caller asked for unless it carries that whole-hertz label, a progressive mode comes before an interlaced one, and the mode in use wins a tie. samples/gfx/video_mode_select checks each of them.
This commit is contained in:
1 parent
f5503fb604
commit
06aed75951
14 files changed
+396
-106
No files matched your search
@@ -952,6 +952,19 @@ jobs:
|
||||
timeout 60 ./wayland_wlr_output_test
|
||||
echo "[pass] wayland_wlr_output_test"
|
||||
|
||||
- name: Build and run video_mode_select_test (ASan + UBSan)
|
||||
shell: bash
|
||||
working-directory: samples/gfx/video_mode_select
|
||||
run: |
|
||||
set -eu
|
||||
# gfx/common/video_mode_select.c: which listed mode a size and
|
||||
# rate name, and the order a resolution list is shown in - the
|
||||
# code every display server's mode switch goes through.
|
||||
make clean all SANITIZER=address,undefined
|
||||
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
|
||||
timeout 60 ./video_mode_select_test
|
||||
echo "[pass] video_mode_select_test"
|
||||
|
||||
- name: Build and run wayland_kwin_output_test (ASan + UBSan)
|
||||
shell: bash
|
||||
working-directory: samples/gfx/wayland_kwin_output
|
||||
|
||||
@@ -1352,6 +1352,7 @@ ifeq ($(HAVE_WAYLAND), 1)
|
||||
gfx/common/wayland_color.o \
|
||||
gfx/common/wayland/kde-output-device-v2.o \
|
||||
gfx/common/wayland/kde-output-management-v2.o \
|
||||
gfx/common/video_mode_select.o \
|
||||
gfx/common/wayland_kwin_output.o \
|
||||
gfx/common/wayland/wlr-output-management-unstable-v1.o \
|
||||
gfx/common/wayland_wlr_output.o \
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include <compat/strl.h>
|
||||
#include <rthreads/rthreads.h>
|
||||
|
||||
#include "video_mode_select.h"
|
||||
|
||||
#include "../../verbosity.h"
|
||||
|
||||
/* libdbus, for the worker's calls only; set before its first. */
|
||||
@@ -639,18 +641,6 @@ static double mdc_nearest_scale(const mdc_mode_t *m, double scale)
|
||||
* Resolution list
|
||||
* ------------------------------------------------------------------ */
|
||||
|
||||
static int mdc_list_qsort(const void *pa, const void *pb)
|
||||
{
|
||||
const video_display_config_t *a = (const video_display_config_t*)pa;
|
||||
const video_display_config_t *b = (const video_display_config_t*)pb;
|
||||
if (a->dims != b->dims)
|
||||
return a->dims < b->dims ? -1 : 1;
|
||||
if (a->interlaced != b->interlaced)
|
||||
return a->interlaced ? 1 : -1;
|
||||
if (a->refreshrate_float != b->refreshrate_float)
|
||||
return a->refreshrate_float < b->refreshrate_float ? -1 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The target head's modes as the menu's list, from a state snapshot. */
|
||||
static enum mutter_dc_result mdc_list_from(const mdc_state_t *st,
|
||||
@@ -700,9 +690,7 @@ static enum mutter_dc_result mdc_list_from(const mdc_state_t *st,
|
||||
if (!dup)
|
||||
conf[n++] = e;
|
||||
}
|
||||
qsort(conf, n, sizeof(*conf), mdc_list_qsort);
|
||||
for (j = 0; j < n; j++)
|
||||
conf[j].idx = j;
|
||||
video_mode_list_finish(conf, n);
|
||||
}
|
||||
|
||||
if (!n)
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "video_mode_select.h"
|
||||
|
||||
int video_mode_find_nearest(void *ctx, video_mode_get_fn get,
|
||||
unsigned count, unsigned dims, int int_hz, float hz)
|
||||
{
|
||||
unsigned i;
|
||||
int best = -1;
|
||||
float best_diff = 0.0f;
|
||||
float want = hz > 0.0f ? hz : (float)int_hz;
|
||||
|
||||
if (!get || !count)
|
||||
return -1;
|
||||
|
||||
/* No rate asked for: the one the display is running */
|
||||
if (want <= 0.0f)
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
video_mode_desc_t m;
|
||||
if (get(ctx, i, &m) && m.current)
|
||||
{
|
||||
want = m.refresh;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
float diff;
|
||||
video_mode_desc_t m;
|
||||
|
||||
if (!get(ctx, i, &m) || m.dims != dims)
|
||||
continue;
|
||||
diff = m.refresh - want;
|
||||
if (diff < 0.0f)
|
||||
diff = -diff;
|
||||
/* Further off than half a hertz is another mode, unless it is
|
||||
* the whole-hertz rate the caller named */
|
||||
if ( want > 0.0f
|
||||
&& diff >= 0.5f
|
||||
&& !(int_hz > 0 && (int)(m.refresh + 0.001f) == int_hz))
|
||||
continue;
|
||||
if (m.interlaced)
|
||||
diff += 1000.0f;
|
||||
if (best < 0 || diff < best_diff || (diff == best_diff && m.current))
|
||||
{
|
||||
best = (int)i;
|
||||
best_diff = diff;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
static int video_mode_list_cmp(const void *pa, const void *pb)
|
||||
{
|
||||
const video_display_config_t *a = (const video_display_config_t*)pa;
|
||||
const video_display_config_t *b = (const video_display_config_t*)pb;
|
||||
if (a->dims != b->dims)
|
||||
return a->dims < b->dims ? -1 : 1;
|
||||
if (a->interlaced != b->interlaced)
|
||||
return a->interlaced ? 1 : -1;
|
||||
if (a->refreshrate_float != b->refreshrate_float)
|
||||
return a->refreshrate_float < b->refreshrate_float ? -1 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void video_mode_list_finish(video_display_config_t *list, unsigned len)
|
||||
{
|
||||
unsigned i;
|
||||
if (!list || !len)
|
||||
return;
|
||||
qsort(list, len, sizeof(*list), video_mode_list_cmp);
|
||||
for (i = 0; i < len; i++)
|
||||
list[i].idx = i;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_VIDEO_MODE_SELECT_H
|
||||
#define __RARCH_VIDEO_MODE_SELECT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <boolean.h>
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#include "../video_display_server.h"
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/* Choosing among a display's modes, as every display server does:
|
||||
* which listed mode a requested size and rate means, and the order the
|
||||
* menu shows them in. The backends keep their own mode structures, so
|
||||
* a mode is read through a callback rather than copied. */
|
||||
|
||||
typedef struct video_mode_desc
|
||||
{
|
||||
/* VIDEO_SCALE_PACK(width, height) */
|
||||
unsigned dims;
|
||||
float refresh;
|
||||
bool interlaced;
|
||||
bool current;
|
||||
} video_mode_desc_t;
|
||||
|
||||
/* Fills 'out' for mode 'index'; false to skip that mode. */
|
||||
typedef bool (*video_mode_get_fn)(void *ctx, unsigned index,
|
||||
video_mode_desc_t *out);
|
||||
|
||||
/**
|
||||
* The listed mode of size 'dims' nearest 'hz': within half a hertz, or
|
||||
* matching 'int_hz' as a whole-hertz label, progressive before
|
||||
* interlaced, and the current mode on a tie. A rate further off than
|
||||
* that is not a mode the caller asked for, so -1 is returned rather
|
||||
* than a wildly different one. -1 also when no mode has that size.
|
||||
*
|
||||
* 'hz' or 'int_hz' at zero takes the current mode's rate.
|
||||
*/
|
||||
int video_mode_find_nearest(void *ctx, video_mode_get_fn get,
|
||||
unsigned count, unsigned dims, int int_hz, float hz);
|
||||
|
||||
/**
|
||||
* Puts a resolution list in the order the menu shows it - by size,
|
||||
* progressive before interlaced, then rate - and numbers the entries.
|
||||
*/
|
||||
void video_mode_list_finish(video_display_config_t *list, unsigned len);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "wayland/kde-output-device-v2.h"
|
||||
#include "wayland/kde-output-management-v2.h"
|
||||
|
||||
#include "video_mode_select.h"
|
||||
|
||||
#include "../../verbosity.h"
|
||||
|
||||
/* The newest versions whose events this file handles */
|
||||
@@ -475,21 +477,22 @@ bool kwin_outputs_ready(const kwin_outputs_t *kw)
|
||||
&& kwin_pick((kwin_outputs_t*)kw, NULL) != NULL;
|
||||
}
|
||||
|
||||
static int kwin_mode_cmp(const void *a, const void *b)
|
||||
/* A mode of the device being asked about, for the shared picker */
|
||||
static bool kwin_mode_desc(void *ctx, unsigned index,
|
||||
video_mode_desc_t *out)
|
||||
{
|
||||
const video_display_config_t *x = (const video_display_config_t*)a;
|
||||
const video_display_config_t *y = (const video_display_config_t*)b;
|
||||
unsigned xw = VIDEO_SCALE_W(x->dims), yw = VIDEO_SCALE_W(y->dims);
|
||||
unsigned xh = VIDEO_SCALE_H(x->dims), yh = VIDEO_SCALE_H(y->dims);
|
||||
if (xw != yw)
|
||||
return xw < yw ? -1 : 1;
|
||||
if (xh != yh)
|
||||
return xh < yh ? -1 : 1;
|
||||
if (x->refreshrate_float != y->refreshrate_float)
|
||||
return x->refreshrate_float < y->refreshrate_float ? -1 : 1;
|
||||
return 0;
|
||||
const kwin_output_device_t *dev = (const kwin_output_device_t*)ctx;
|
||||
const kwin_output_mode_t *m = &dev->modes[index];
|
||||
if (m->width <= 0 || m->height <= 0 || m->refresh_mhz <= 0)
|
||||
return false;
|
||||
out->dims = VIDEO_SCALE_PACK(m->width, m->height);
|
||||
out->refresh = (float)m->refresh_mhz / 1000.0f;
|
||||
out->interlaced = false;
|
||||
out->current = (m->mode == dev->current);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
video_display_config_t *kwin_outputs_resolution_list(kwin_outputs_t *kw,
|
||||
const char *connector, unsigned *len)
|
||||
{
|
||||
@@ -515,9 +518,7 @@ video_display_config_t *kwin_outputs_resolution_list(kwin_outputs_t *kw,
|
||||
list[n].current = (m->mode == dev->current);
|
||||
n++;
|
||||
}
|
||||
qsort(list, n, sizeof(*list), kwin_mode_cmp);
|
||||
for (i = 0; i < n; i++)
|
||||
list[i].idx = i;
|
||||
video_mode_list_finish(list, n);
|
||||
*len = n;
|
||||
return list;
|
||||
}
|
||||
@@ -525,49 +526,33 @@ video_display_config_t *kwin_outputs_resolution_list(kwin_outputs_t *kw,
|
||||
bool kwin_outputs_set_mode(kwin_outputs_t *kw, const char *connector,
|
||||
unsigned width, unsigned height, int int_hz, float hz)
|
||||
{
|
||||
unsigned i;
|
||||
float want_hz;
|
||||
int pick;
|
||||
struct kde_output_configuration_v2 *config;
|
||||
const kwin_output_mode_t *cur = NULL;
|
||||
const kwin_output_mode_t *best = NULL;
|
||||
kwin_output_device_t *dev = NULL;
|
||||
|
||||
if (!kw || !kw->management || !(dev = kwin_pick(kw, connector)))
|
||||
return false;
|
||||
for (i = 0; i < dev->nmodes; i++)
|
||||
if (dev->modes[i].mode == dev->current)
|
||||
cur = &dev->modes[i];
|
||||
if (!width)
|
||||
width = cur ? (unsigned)cur->width : 0;
|
||||
if (!height)
|
||||
height = cur ? (unsigned)cur->height : 0;
|
||||
want_hz = hz > 0.0f ? hz : (float)int_hz;
|
||||
if (want_hz <= 0.0f && cur)
|
||||
want_hz = (float)cur->refresh_mhz / 1000.0f;
|
||||
|
||||
/* The listed mode of that size nearest the rate */
|
||||
for (i = 0; i < dev->nmodes; i++)
|
||||
if (!width || !height)
|
||||
{
|
||||
const kwin_output_mode_t *m = &dev->modes[i];
|
||||
float d, bd;
|
||||
if ((unsigned)m->width != width || (unsigned)m->height != height)
|
||||
continue;
|
||||
if (!best)
|
||||
{
|
||||
best = m;
|
||||
continue;
|
||||
}
|
||||
d = (float)m->refresh_mhz / 1000.0f - want_hz;
|
||||
bd = (float)best->refresh_mhz / 1000.0f - want_hz;
|
||||
if ((d < 0 ? -d : d) < (bd < 0 ? -bd : bd))
|
||||
best = m;
|
||||
unsigned i;
|
||||
for (i = 0; i < dev->nmodes; i++)
|
||||
if (dev->modes[i].mode == dev->current)
|
||||
{
|
||||
if (!width)
|
||||
width = (unsigned)dev->modes[i].width;
|
||||
if (!height)
|
||||
height = (unsigned)dev->modes[i].height;
|
||||
}
|
||||
}
|
||||
if (!best)
|
||||
if ((pick = video_mode_find_nearest(dev, kwin_mode_desc, dev->nmodes,
|
||||
VIDEO_SCALE_PACK(width, height), int_hz, hz)) < 0)
|
||||
{
|
||||
RARCH_WARN("[Wayland] KWin lists no %ux%u mode on %s.\n",
|
||||
width, height, dev->name[0] ? dev->name : "its output");
|
||||
return false;
|
||||
}
|
||||
best = &dev->modes[pick];
|
||||
if (best->mode == dev->current)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "wayland_wlr_output.h"
|
||||
#include "wayland/wlr-output-management-unstable-v1.h"
|
||||
|
||||
#include "video_mode_select.h"
|
||||
|
||||
#include "../../verbosity.h"
|
||||
|
||||
/* The newest version whose events this file handles */
|
||||
@@ -341,21 +343,22 @@ bool wlr_outputs_ready(const wlr_outputs_t *wo)
|
||||
&& wlr_pick((wlr_outputs_t*)wo, NULL) != NULL;
|
||||
}
|
||||
|
||||
static int wlr_mode_cmp(const void *a, const void *b)
|
||||
/* A mode of the head being asked about, for the shared picker */
|
||||
static bool wlr_mode_desc(void *ctx, unsigned index,
|
||||
video_mode_desc_t *out)
|
||||
{
|
||||
const video_display_config_t *x = (const video_display_config_t*)a;
|
||||
const video_display_config_t *y = (const video_display_config_t*)b;
|
||||
unsigned xw = VIDEO_SCALE_W(x->dims), yw = VIDEO_SCALE_W(y->dims);
|
||||
unsigned xh = VIDEO_SCALE_H(x->dims), yh = VIDEO_SCALE_H(y->dims);
|
||||
if (xw != yw)
|
||||
return xw < yw ? -1 : 1;
|
||||
if (xh != yh)
|
||||
return xh < yh ? -1 : 1;
|
||||
if (x->refreshrate_float != y->refreshrate_float)
|
||||
return x->refreshrate_float < y->refreshrate_float ? -1 : 1;
|
||||
return 0;
|
||||
const wlr_output_head_info_t *h = (const wlr_output_head_info_t*)ctx;
|
||||
const wlr_output_mode_info_t *m = &h->modes[index];
|
||||
if (m->width <= 0 || m->height <= 0 || m->refresh_mhz <= 0)
|
||||
return false;
|
||||
out->dims = VIDEO_SCALE_PACK(m->width, m->height);
|
||||
out->refresh = (float)m->refresh_mhz / 1000.0f;
|
||||
out->interlaced = false;
|
||||
out->current = (m->mode == h->current);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
video_display_config_t *wlr_outputs_resolution_list(wlr_outputs_t *wo,
|
||||
const char *connector, unsigned *len)
|
||||
{
|
||||
@@ -380,9 +383,7 @@ video_display_config_t *wlr_outputs_resolution_list(wlr_outputs_t *wo,
|
||||
list[n].current = (m->mode == h->current);
|
||||
n++;
|
||||
}
|
||||
qsort(list, n, sizeof(*list), wlr_mode_cmp);
|
||||
for (i = 0; i < n; i++)
|
||||
list[i].idx = i;
|
||||
video_mode_list_finish(list, n);
|
||||
*len = n;
|
||||
return list;
|
||||
}
|
||||
@@ -391,48 +392,31 @@ bool wlr_outputs_set_mode(wlr_outputs_t *wo, const char *connector,
|
||||
unsigned width, unsigned height, int int_hz, float hz)
|
||||
{
|
||||
unsigned i;
|
||||
float want_hz;
|
||||
int pick;
|
||||
struct zwlr_output_configuration_v1 *config;
|
||||
const wlr_output_mode_info_t *cur = NULL;
|
||||
const wlr_output_mode_info_t *best = NULL;
|
||||
wlr_output_head_info_t *target = NULL;
|
||||
|
||||
if (!wlr_outputs_ready(wo) || !(target = wlr_pick(wo, connector)))
|
||||
return false;
|
||||
for (i = 0; i < target->nmodes; i++)
|
||||
if (target->modes[i].mode == target->current)
|
||||
cur = &target->modes[i];
|
||||
if (!width)
|
||||
width = cur ? (unsigned)cur->width : 0;
|
||||
if (!height)
|
||||
height = cur ? (unsigned)cur->height : 0;
|
||||
want_hz = hz > 0.0f ? hz : (float)int_hz;
|
||||
if (want_hz <= 0.0f && cur)
|
||||
want_hz = (float)cur->refresh_mhz / 1000.0f;
|
||||
|
||||
/* The listed mode of that size nearest the rate */
|
||||
for (i = 0; i < target->nmodes; i++)
|
||||
{
|
||||
const wlr_output_mode_info_t *m = &target->modes[i];
|
||||
float d, bd;
|
||||
if ((unsigned)m->width != width || (unsigned)m->height != height)
|
||||
continue;
|
||||
if (!best)
|
||||
{
|
||||
best = m;
|
||||
continue;
|
||||
}
|
||||
d = (float)m->refresh_mhz / 1000.0f - want_hz;
|
||||
bd = (float)best->refresh_mhz / 1000.0f - want_hz;
|
||||
if ((d < 0 ? -d : d) < (bd < 0 ? -bd : bd))
|
||||
best = m;
|
||||
}
|
||||
if (!best)
|
||||
if (!width || !height)
|
||||
for (i = 0; i < target->nmodes; i++)
|
||||
if (target->modes[i].mode == target->current)
|
||||
{
|
||||
if (!width)
|
||||
width = (unsigned)target->modes[i].width;
|
||||
if (!height)
|
||||
height = (unsigned)target->modes[i].height;
|
||||
}
|
||||
if ((pick = video_mode_find_nearest(target, wlr_mode_desc,
|
||||
target->nmodes, VIDEO_SCALE_PACK(width, height),
|
||||
int_hz, hz)) < 0)
|
||||
{
|
||||
RARCH_WARN("[Wayland] The compositor lists no %ux%u mode on %s.\n",
|
||||
width, height, target->name[0] ? target->name : "its output");
|
||||
return false;
|
||||
}
|
||||
best = &target->modes[pick];
|
||||
if (best->mode == target->current)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -1475,6 +1475,7 @@ THREAD
|
||||
|| defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
#include "../gfx/common/dbus_runtime.c"
|
||||
#include "../gfx/common/dbus_common.c"
|
||||
#include "../gfx/common/video_mode_select.c"
|
||||
#include "../gfx/common/mutter_displayconfig.c"
|
||||
#include "../frontend/thread_elevation/rtkit.c"
|
||||
#include "../frontend/thread_elevation/eevdf.c"
|
||||
|
||||
@@ -26,6 +26,7 @@ SOURCES := mutter_displayconfig_test.c \
|
||||
$(LRC)/rthreads/rthreads.c \
|
||||
$(LRC)/dynamic/dylib.c \
|
||||
$(REPO_ROOT)/gfx/common/wayland_kwin_output.c \
|
||||
$(REPO_ROOT)/gfx/common/video_mode_select.c \
|
||||
kde-output-device-v2-protocol.c \
|
||||
kde-output-management-v2-protocol.c \
|
||||
$(REPO_ROOT)/gfx/common/wayland_wlr_output.c \
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# gfx/common/video_mode_select.c: which listed mode a requested size and
|
||||
# rate means, and the order the menu shows a resolution list in - the
|
||||
# code every display server's mode switch now goes through.
|
||||
|
||||
TARGET := video_mode_select_test
|
||||
REPO_ROOT := ../../..
|
||||
SOURCES := video_mode_select_test.c $(REPO_ROOT)/gfx/common/video_mode_select.c
|
||||
CFLAGS += -Wall -std=gnu99 -g -O0 -DRARCH_INTERNAL \
|
||||
-I$(REPO_ROOT) -I$(REPO_ROOT)/libretro-common/include
|
||||
ifneq ($(SANITIZER),)
|
||||
CFLAGS := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)
|
||||
LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)
|
||||
endif
|
||||
|
||||
all: $(TARGET)
|
||||
$(TARGET): $(SOURCES)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
check: $(TARGET)
|
||||
./$(TARGET)
|
||||
clean:
|
||||
rm -f $(TARGET)
|
||||
.PHONY: all check clean
|
||||
@@ -0,0 +1,138 @@
|
||||
/* gfx/common/video_mode_select.c: the mode a size and rate name, and
|
||||
* the order a resolution list is shown in. Every display server -
|
||||
* Mutter, KWin, wlroots - switches modes through this, so the rules it
|
||||
* applies are checked here rather than three times over. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gfx/common/video_mode_select.h"
|
||||
|
||||
/* A display's modes, as any backend would hold them */
|
||||
typedef struct { int w, h; float hz; bool interlaced, current; } mode_t_;
|
||||
|
||||
static mode_t_ modes[] = {
|
||||
{ 1920, 1080, 60.000f, false, false },
|
||||
{ 1920, 1080, 59.940f, false, true }, /* the one running */
|
||||
{ 1920, 1080, 120.000f, false, false },
|
||||
{ 1920, 1080, 60.000f, true, false }, /* interlaced twin */
|
||||
{ 1280, 720, 60.000f, false, false },
|
||||
{ 2560, 1440, 143.998f, false, false },
|
||||
{ 0, 0, 0.000f, false, false }, /* a mode with nothing in it */
|
||||
};
|
||||
#define NMODES ((unsigned)(sizeof(modes) / sizeof(modes[0])))
|
||||
|
||||
static bool get(void *ctx, unsigned i, video_mode_desc_t *out)
|
||||
{
|
||||
const mode_t_ *m = &((const mode_t_*)ctx)[i];
|
||||
if (m->w <= 0 || m->h <= 0 || m->hz <= 0.0f)
|
||||
return false;
|
||||
out->dims = VIDEO_SCALE_PACK(m->w, m->h);
|
||||
out->refresh = m->hz;
|
||||
out->interlaced = m->interlaced;
|
||||
out->current = m->current;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int fails;
|
||||
static void check(const char *what, int ok)
|
||||
{
|
||||
printf(" %s %s\n", ok ? "ok " : "FAIL", what);
|
||||
if (!ok)
|
||||
fails++;
|
||||
}
|
||||
static int pick(int w, int h, int int_hz, float hz)
|
||||
{
|
||||
return video_mode_find_nearest(modes, get, NMODES,
|
||||
VIDEO_SCALE_PACK(w, h), int_hz, hz);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("1. the mode a size and rate name\n");
|
||||
check("an exact rate", pick(1920, 1080, 120, 120.0f) == 2);
|
||||
check("59.94 asked for as 59.94", pick(1920, 1080, 60, 59.94f) == 1);
|
||||
check("60 asked for takes 60.000, not the running 59.94",
|
||||
pick(1920, 1080, 60, 60.0f) == 0);
|
||||
check("a whole-hertz label matches a rate further than half a hertz off",
|
||||
pick(2560, 1440, 144, 144.0f) == 5);
|
||||
check("another size", pick(1280, 720, 60, 60.0f) == 4);
|
||||
|
||||
printf("2. what is not a mode the caller asked for\n");
|
||||
check("a rate no mode is near", pick(1920, 1080, 0, 75.0f) == -1);
|
||||
check("a size no mode has", pick(1024, 768, 60, 60.0f) == -1);
|
||||
check("a mode with nothing in it is skipped", pick(0, 0, 60, 60.0f) == -1);
|
||||
check("no modes at all",
|
||||
video_mode_find_nearest(modes, get, 0, VIDEO_SCALE_PACK(1920, 1080),
|
||||
60, 60.0f) == -1);
|
||||
check("no getter", video_mode_find_nearest(modes, NULL, NMODES,
|
||||
VIDEO_SCALE_PACK(1920, 1080), 60, 60.0f) == -1);
|
||||
|
||||
printf("3. progressive before interlaced, the running mode on a tie\n");
|
||||
check("60.000 progressive beats its interlaced twin",
|
||||
pick(1920, 1080, 60, 60.0f) == 0);
|
||||
{
|
||||
/* the progressive 60 gone, a progressive 59.94 is still nearer
|
||||
* than an interlaced 60 */
|
||||
mode_t_ saved = modes[0];
|
||||
modes[0].hz = 0.0f;
|
||||
check("a progressive neighbour beats an interlaced exact match",
|
||||
pick(1920, 1080, 60, 60.0f) == 1);
|
||||
modes[0] = saved;
|
||||
}
|
||||
{
|
||||
/* nothing progressive at that size: the interlaced one it is */
|
||||
mode_t_ s0 = modes[0], s1 = modes[1], s2 = modes[2];
|
||||
modes[0].hz = modes[1].hz = modes[2].hz = 0.0f;
|
||||
check("an interlaced mode is used when it is the only one",
|
||||
pick(1920, 1080, 60, 60.0f) == 3);
|
||||
modes[0] = s0; modes[1] = s1; modes[2] = s2;
|
||||
}
|
||||
{
|
||||
/* two identical rates, one of them running */
|
||||
mode_t_ saved = modes[2];
|
||||
modes[2].hz = 59.940f;
|
||||
check("the running mode wins a tie", pick(1920, 1080, 60, 59.94f) == 1);
|
||||
modes[2] = saved;
|
||||
}
|
||||
|
||||
printf("4. no rate asked for means the rate in use\n");
|
||||
check("size only takes the running 59.94", pick(1920, 1080, 0, 0.0f) == 1);
|
||||
|
||||
printf("5. the order the menu shows a list in\n");
|
||||
{
|
||||
video_display_config_t list[4];
|
||||
unsigned i;
|
||||
memset(list, 0, sizeof(list));
|
||||
list[0].dims = VIDEO_SCALE_PACK(1920, 1080);
|
||||
list[0].refreshrate_float = 120.0f;
|
||||
list[1].dims = VIDEO_SCALE_PACK(1280, 720);
|
||||
list[1].refreshrate_float = 60.0f;
|
||||
list[2].dims = VIDEO_SCALE_PACK(1920, 1080);
|
||||
list[2].refreshrate_float = 60.0f;
|
||||
list[2].interlaced = true;
|
||||
list[3].dims = VIDEO_SCALE_PACK(1920, 1080);
|
||||
list[3].refreshrate_float = 60.0f;
|
||||
video_mode_list_finish(list, 4);
|
||||
check("by size, then progressive, then rate",
|
||||
VIDEO_SCALE_W(list[0].dims) == 1280
|
||||
&& VIDEO_SCALE_W(list[1].dims) == 1920 && list[1].refreshrate_float == 60.0f && !list[1].interlaced
|
||||
&& VIDEO_SCALE_W(list[2].dims) == 1920 && list[2].refreshrate_float == 120.0f
|
||||
&& list[3].interlaced);
|
||||
for (i = 0; i < 4; i++)
|
||||
if (list[i].idx != i)
|
||||
break;
|
||||
check("numbered in that order", i == 4);
|
||||
video_mode_list_finish(NULL, 4);
|
||||
video_mode_list_finish(list, 0);
|
||||
check("nothing to sort is harmless", 1);
|
||||
}
|
||||
|
||||
if (fails)
|
||||
{
|
||||
printf("video_mode_select: %d check(s) failed\n", fails);
|
||||
return 1;
|
||||
}
|
||||
printf("video_mode_select: all checks passed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -33,6 +33,7 @@ SOURCES := wayland_drm_lease_test.c \
|
||||
$(REPO_ROOT)/gfx/display_servers/dispserv_wl.c \
|
||||
$(REPO_ROOT)/gfx/common/wayland_drm_lease.c \
|
||||
$(REPO_ROOT)/gfx/common/wayland_kwin_output.c \
|
||||
$(REPO_ROOT)/gfx/common/video_mode_select.c \
|
||||
kde-output-device-v2-protocol.c \
|
||||
kde-output-management-v2-protocol.c \
|
||||
$(REPO_ROOT)/gfx/common/wayland_wlr_output.c \
|
||||
|
||||
@@ -15,6 +15,7 @@ GENERATED := kde-output-device-v2-server-protocol.h \
|
||||
SOURCES := wayland_kwin_output_test.c \
|
||||
kde-output-device-v2-protocol.c kde-output-management-v2-protocol.c \
|
||||
$(REPO_ROOT)/gfx/common/wayland_kwin_output.c \
|
||||
$(REPO_ROOT)/gfx/common/video_mode_select.c \
|
||||
$(LRC)/compat/compat_strl.c
|
||||
CFLAGS += -Wall -std=gnu99 -g -O0 -DRARCH_INTERNAL -DHAVE_WAYLAND -D_GNU_SOURCE \
|
||||
-I. -I$(REPO_ROOT) -I$(LRC)/include \
|
||||
|
||||
@@ -13,6 +13,7 @@ GENERATED := wlr-output-management-unstable-v1-server-protocol.h \
|
||||
SOURCES := wayland_wlr_output_test.c \
|
||||
wlr-output-management-unstable-v1-protocol.c \
|
||||
$(REPO_ROOT)/gfx/common/wayland_wlr_output.c \
|
||||
$(REPO_ROOT)/gfx/common/video_mode_select.c \
|
||||
$(LRC)/compat/compat_strl.c
|
||||
CFLAGS += -Wall -std=gnu99 -g -O0 -DRARCH_INTERNAL -DHAVE_WAYLAND -D_GNU_SOURCE \
|
||||
-I. -I$(REPO_ROOT) -I$(LRC)/include \
|
||||
|
||||
Reference in new issue
Block a user