summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2023-11-30 11:50:26 -0800
committerVito Caputo <vcaputo@pengaru.com>2023-11-30 11:50:26 -0800
commit878514e85a987f267250838398d4e27e44016ec5 (patch)
tree3e46cb229c1b5f7627bdc41418e3ee0d7f479446
parent28d12a899645be09dae7e4cb8c293bf7fc64d6ad (diff)
til,main: introduce ratio= --video setting
First stab at supporting explicit aspect ratios. This performs the adjustment when needed in til_fb so it's automatically applied to all fb backends. The syntax is ratio=W:H with ratio=full being special cased for when no aspect ratio adjustment is desired (just use whatever the fb page dimensions are, usually specified via size= in the fb backend's settings, or display native res when fullscreen=on) For now when an aspect ratio is specified it always fits the content within the alotted space... there is no full-but-ratio-preserved-by-clipping-if-needed variant like widescreen TVs often have.
-rw-r--r--src/main.c69
-rw-r--r--src/til_fb.c59
-rw-r--r--src/til_video_setup.h2
3 files changed, 122 insertions, 8 deletions
diff --git a/src/main.c b/src/main.c
index df2d219..28f897f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <sys/time.h>
#include <unistd.h>
+#include <math.h>
#include "til.h"
#include "til_args.h"
@@ -24,7 +25,7 @@
/* Copyright (C) 2016 Vito Caputo <vcaputo@pengaru.com> */
-#define NUM_FB_PAGES 3
+#define NUM_FB_PAGES 3
/* ^ By triple-buffering, we can have a page tied up being displayed, another
* tied up submitted and waiting for vsync, and still not block on getting
* another page so we can begin rendering another frame before vsync. With
@@ -33,30 +34,33 @@
#ifndef DEFAULT_VIDEO
#ifdef HAVE_SDL
-#define DEFAULT_VIDEO "sdl"
+#define DEFAULT_VIDEO "sdl"
#endif
#endif
#ifndef DEFAULT_VIDEO
#ifdef HAVE_DRM
-#define DEFAULT_VIDEO "drm"
+#define DEFAULT_VIDEO "drm"
#endif
#endif
#ifndef DEFAULT_VIDEO
-#define DEFAULT_VIDEO "mem"
+#define DEFAULT_VIDEO "mem"
#endif
+#define DEFAULT_VIDEO_RATIO "full"
+
#ifndef DEFAULT_AUDIO
#ifdef HAVE_SDL
-#define DEFAULT_AUDIO "sdl"
+#define DEFAULT_AUDIO "sdl"
#endif
#endif
#ifndef DEFAULT_AUDIO
-#define DEFAULT_AUDIO "mem"
+#define DEFAULT_AUDIO "mem"
#endif
+
extern til_fb_ops_t drm_fb_ops;
extern til_fb_ops_t mem_fb_ops;
extern til_fb_ops_t sdl_fb_ops;
@@ -153,6 +157,33 @@ static int setup_audio(const til_settings_t *settings, til_setting_t **res_setti
static int setup_video(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup)
{
til_setting_t *setting;
+ til_setting_t *ratio;
+ const char *ratio_values[] = {
+ "full",
+ "1:1",
+ "4:3",
+ "3:2",
+ "16:10",
+ "5:3",
+ "16:9",
+ "2:1",
+ "21:9",
+ "32:9",
+ NULL
+ };
+ const char *ratio_annotations[] = {
+ "Fill fb with content, inheriting its ratio as-is (may stretch)",
+ "Square",
+ "CRT Monitor/TV (VGA/XGA)",
+ "35mm film, iphone",
+ "Widescreen monitor (WXGA)",
+ "Super 16mm film",
+ "Widescreen TV / newer laptops",
+ "Dominoes",
+ "Ultra-widescreen",
+ "Super ultra-widescreen",
+ NULL
+ };
const char *video;
int r;
@@ -188,6 +219,21 @@ static int setup_video(const til_settings_t *settings, til_setting_t **res_setti
return 1;
}
+ r = til_settings_get_and_describe_setting(settings,
+ &(til_setting_spec_t){
+ .name = "Content aspect ratio (W:H)",
+ .key = "ratio",
+ .preferred = DEFAULT_VIDEO_RATIO,
+ .values = ratio_values,
+ .annotations = ratio_annotations,
+ },
+ &ratio,
+ res_setting,
+ res_desc);
+ if (r)
+ return r;
+
+
/* XXX: this is kind of hacky for now */
#ifdef HAVE_DRM
if (!strcasecmp(video, "drm"))
@@ -215,6 +261,17 @@ static int setup_video(const til_settings_t *settings, til_setting_t **res_setti
if (r)
return r;
+ if (!strcasecmp(ratio->value, "full"))
+ setup->ratio = NAN;
+ else {
+ float w, h;
+
+ if (sscanf(ratio->value, "%f:%f", &w, &h) != 2)
+ return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, ratio, res_setting, -EINVAL);
+
+ setup->ratio = w / h;
+ }
+
*res_setup = &setup->til_setup;
}
diff --git a/src/til_fb.c b/src/til_fb.c
index 3c19ae5..cc07909 100644
--- a/src/til_fb.c
+++ b/src/til_fb.c
@@ -1,4 +1,5 @@
#include <assert.h>
+#include <math.h>
#include <pthread.h>
#include <stddef.h>
#include <stdlib.h>
@@ -126,6 +127,7 @@ typedef struct til_fb_t {
const til_fb_ops_t *ops;
void *ops_context;
int n_pages;
+ float ratio;
pthread_mutex_t rebuild_mutex;
int rebuild_pages; /* counter of pages needing a rebuild */
@@ -157,6 +159,48 @@ typedef struct til_fb_t {
static _til_fb_page_t * _til_fb_page_alloc(til_fb_t *fb);
+/* apply an aspect ratio to a fragment's frame,
+ * if ratio=NAN then the fragment is used as-is (e.g. for "ratio=full").
+ */
+static _til_fb_page_t * _til_fb_page_apply_ratio(_til_fb_page_t *page)
+{
+ til_fb_fragment_t *fragment;
+ float fragment_ratio, d;
+ float ratio;
+
+ assert(page);
+ assert(page->fb);
+
+ ratio = page->fb->ratio;
+ fragment = &page->fragment.public;
+
+ assert(fragment->frame_width > 0 && fragment->frame_height > 0);
+ assert(ratio > 0.f);
+
+ if (isnan(ratio))
+ return page;
+
+ fragment_ratio = (float)fragment->frame_width / (float)fragment->frame_height;
+ d = fragment_ratio - ratio;
+ if (d < 0) { /* letterboxed, scale height */
+ unsigned h = fragment->frame_width / ratio;
+
+ fragment->buf += ((fragment->frame_height - h) / 2) * fragment->pitch;
+ fragment->frame_height = h;
+ fragment->height = h;
+ } else if (d > 0) { /* pillarboxed, scale width */
+ unsigned w = fragment->frame_height * ratio;
+
+ fragment->buf += ((fragment->frame_width - w) / 2);
+ fragment->stride += fragment->frame_width - w;
+ fragment->frame_width = w;
+ fragment->width = w;
+ }
+
+ return page;
+}
+
+
/* Consumes ready pages queued via til_fb_page_put(), submits them to drm to flip
* on vsync. Produces inactive pages from those replaced, making them
* available to til_fb_page_get(). */
@@ -205,6 +249,8 @@ int til_fb_flip(til_fb_t *fb)
fb->ops->page_free(fb, fb->ops_context, p->fb_ops_page);
p->fb_ops_page = fb->ops->page_alloc(fb, fb->ops_context, &p->fragment.public);
p->fragment.public.ops = &p->fragment.ops;
+ _til_fb_page_apply_ratio(p);
+
fb->rebuild_pages--;
}
pthread_mutex_unlock(&fb->rebuild_mutex);
@@ -366,7 +412,7 @@ static _til_fb_page_t * _til_fb_page_alloc(til_fb_t *fb)
else
fb->all_pages_tail = page;
- return page;
+ return _til_fb_page_apply_ratio(page);
}
@@ -561,7 +607,7 @@ int til_fb_new(const til_fb_ops_t *ops, const char *title, const til_video_setup
assert(ops->page_alloc);
assert(ops->page_free);
assert(ops->page_flip);
- assert(!setup && setup->til_setup.creator == ops);
+ assert(setup && setup->til_setup.creator == ops);
assert(n_pages > 1);
assert(res_fb);
@@ -580,6 +626,15 @@ int til_fb_new(const til_fb_ops_t *ops, const char *title, const til_video_setup
goto fail;
}
+ /* TODO: fb should probably just take a reference on the setup,
+ * the whole distinction of the ops-specific setup and intermediate
+ * fb-common setup needs clarification, it's rather muddy right now esp.
+ * with the advent of til_video_setup_t to facilitate a common ratio=
+ * setting... with the backend allocating the whole setup, when it only
+ * performs setup of its own little subset. This all needs some tidying up
+ * now that things have evolved so much on the video/fb side.
+ */
+ fb->ratio = setup->ratio;
pthread_mutex_init(&fb->ready_mutex, NULL);
pthread_cond_init(&fb->ready_cond, NULL);
pthread_mutex_init(&fb->inactive_mutex, NULL);
diff --git a/src/til_video_setup.h b/src/til_video_setup.h
index 21c5844..f774c6f 100644
--- a/src/til_video_setup.h
+++ b/src/til_video_setup.h
@@ -5,6 +5,8 @@
typedef struct til_video_setup_t {
til_setup_t til_setup;
+
+ float ratio;
} til_video_setup_t;
#endif
© All Rights Reserved