summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2022-04-28 01:46:10 -0700
committerVito Caputo <vcaputo@pengaru.com>2022-05-01 21:02:41 -0700
commita59229c5513e73348c87bcfc5cc4b39a31012437 (patch)
tree09cbc567f883b8f8677f689f658cd747ca360706
parent7dec62422b3b00f9a347d37f1e7f89e5bbaba0a9 (diff)
til_fb: introduce a fragment texture source
Idea here is to provide texture sources for obtaining pixel colors at the til_fb_put_pixel/fill drawing API, making it possible for at least overlayable modules to serve as mask/stencil operators where their drawn areas are populated by the contents of another fragment produced dynamically, potentially by other modules altogether. This commit adds a texture=modulename option to the compose module for specifying if a texture should be used when compositing, excepting and defaulting to "none" for disabling texturing. A future commit should expand this compose option to accept a potential list of modules for composing the texture in the same way as the main layers= list functions. Something this all immediately makes clear is the need for a better settings syntax, probably in the form of all module setting specifiers optionally being followed by a squence of settings, with support for escaping to handle nested situations.
-rw-r--r--src/drm_fb.c16
-rw-r--r--src/modules/blinds/blinds.c14
-rw-r--r--src/modules/compose/compose.c100
-rw-r--r--src/modules/montage/montage.c25
-rw-r--r--src/sdl_fb.c16
-rw-r--r--src/til_fb.c50
-rw-r--r--src/til_fb.h75
7 files changed, 229 insertions, 67 deletions
diff --git a/src/drm_fb.c b/src/drm_fb.c
index 927f46c..a60f1e7 100644
--- a/src/drm_fb.c
+++ b/src/drm_fb.c
@@ -487,13 +487,15 @@ static void * drm_fb_page_alloc(til_fb_t *fb, void *context, til_fb_page_t *res_
p->drm_dumb_handle = map_dumb.handle;
p->drm_fb_id = fb_id;
- res_page->fragment.buf = map;
- res_page->fragment.width = c->mode->hdisplay;
- res_page->fragment.frame_width = c->mode->hdisplay;
- res_page->fragment.height = c->mode->vdisplay;
- res_page->fragment.frame_height = c->mode->vdisplay;
- res_page->fragment.pitch = create_dumb.pitch >> 2;
- res_page->fragment.stride = res_page->fragment.pitch - (c->mode->hdisplay);
+ *res_page = (til_fb_page_t){
+ .fragment.buf = map,
+ .fragment.width = c->mode->hdisplay,
+ .fragment.frame_width = c->mode->hdisplay,
+ .fragment.height = c->mode->vdisplay,
+ .fragment.frame_height = c->mode->vdisplay,
+ .fragment.pitch = create_dumb.pitch >> 2,
+ .fragment.stride = (create_dumb.pitch >> 2) - c->mode->hdisplay,
+ };
return p;
}
diff --git a/src/modules/blinds/blinds.c b/src/modules/blinds/blinds.c
index b14997e..0a8342e 100644
--- a/src/modules/blinds/blinds.c
+++ b/src/modules/blinds/blinds.c
@@ -66,8 +66,11 @@ static inline void draw_blind_horizontal(til_fb_fragment_t *fragment, unsigned r
unsigned row_height = fragment->frame_height / count;
unsigned height = roundf(t * (float)row_height);
- for (unsigned y = 0; y < height; y++)
- memset(fragment->buf + ((row * row_height) + y ) * fragment->pitch, 0xff, fragment->width * 4);
+/* XXX FIXME: use faster block style fill/copy if til_fb gets that */
+ for (unsigned y = 0; y < height; y++) {
+ for (unsigned x = 0; x < fragment->width; x++)
+ til_fb_fragment_put_pixel_unchecked(fragment, fragment->x + x, fragment->y + y + row * row_height, 0xffffffff);
+ }
}
@@ -77,8 +80,11 @@ static inline void draw_blind_vertical(til_fb_fragment_t *fragment, unsigned col
unsigned column_width = fragment->frame_width / count;
unsigned width = roundf(t * (float)column_width);
- for (unsigned y = 0; y < fragment->height; y++)
- memset(fragment->buf + y * fragment->pitch + column * column_width, 0xff, width * 4);
+/* XXX FIXME: use faster block style fill/copy if til_fb gets that */
+ for (unsigned y = 0; y < fragment->height; y++) {
+ for (unsigned x = 0; x < width; x++)
+ til_fb_fragment_put_pixel_unchecked(fragment, fragment->x + x + column * column_width, fragment->y + y, 0xffffffff);
+ }
}
diff --git a/src/modules/compose/compose.c b/src/modules/compose/compose.c
index d672bf0..a331b3f 100644
--- a/src/modules/compose/compose.c
+++ b/src/modules/compose/compose.c
@@ -33,12 +33,15 @@ typedef struct compose_layer_t {
typedef struct compose_context_t {
unsigned n_cpus;
+ til_fb_fragment_t texture_fb;
+ compose_layer_t texture;
size_t n_layers;
compose_layer_t layers[];
} compose_context_t;
typedef struct compose_setup_t {
til_setup_t til_setup;
+ char *texture;
size_t n_layers;
char *layers[];
} compose_setup_t;
@@ -93,6 +96,16 @@ static void * compose_create_context(unsigned ticks, unsigned n_cpus, til_setup_
ctxt->n_layers++;
}
+ if (((compose_setup_t *)setup)->texture) {
+ til_setup_t *texture_setup = NULL;
+
+ ctxt->texture.module = til_lookup_module(((compose_setup_t *)setup)->texture);
+ (void) til_module_randomize_setup(ctxt->texture.module, &texture_setup, NULL);
+
+ (void) til_module_create_context(ctxt->texture.module, ticks, texture_setup, &ctxt->texture.module_ctxt);
+ til_setup_free(texture_setup);
+ }
+
return ctxt;
}
@@ -103,6 +116,12 @@ static void compose_destroy_context(void *context)
for (int i = 0; i < ctxt->n_layers; i++)
til_module_destroy_context(ctxt->layers[i].module, ctxt->layers[i].module_ctxt);
+
+ if (ctxt->texture.module)
+ til_module_destroy_context(ctxt->texture.module, ctxt->texture.module_ctxt);
+
+ free(ctxt->texture_fb.buf);
+
free(context);
}
@@ -113,8 +132,38 @@ static void compose_prepare_frame(void *context, unsigned ticks, unsigned n_cpus
til_fb_fragment_clear(fragment);
- for (int i = 0; i < ctxt->n_layers; i++)
- til_module_render(ctxt->layers[i].module, ctxt->layers[i].module_ctxt, ticks, fragment);
+ if (ctxt->texture.module) {
+ if (!ctxt->texture_fb.buf ||
+ ctxt->texture_fb.frame_width != fragment->frame_width ||
+ ctxt->texture_fb.frame_height != fragment->frame_height) {
+
+ ctxt->texture_fb = (til_fb_fragment_t){
+ .buf = realloc(ctxt->texture_fb.buf, fragment->frame_height * fragment->frame_width * sizeof(uint32_t)),
+
+ .frame_width = fragment->frame_width,
+ .frame_height = fragment->frame_height,
+ .width = fragment->frame_width,
+ .height = fragment->frame_height,
+ .pitch = fragment->frame_width,
+ };
+ }
+
+ ctxt->texture_fb.cleared = 0;
+ til_module_render(ctxt->texture.module, ctxt->texture.module_ctxt, ticks, &ctxt->texture_fb);
+
+ til_module_render(ctxt->layers[0].module, ctxt->layers[0].module_ctxt, ticks, fragment);
+
+ for (size_t i = 1; i < ctxt->n_layers; i++) {
+ til_fb_fragment_t textured = *fragment;
+
+ textured.texture = &ctxt->texture_fb;
+
+ til_module_render(ctxt->layers[i].module, ctxt->layers[i].module_ctxt, ticks, &textured);
+ }
+ } else {
+ for (size_t i = 0; i < ctxt->n_layers; i++)
+ til_module_render(ctxt->layers[i].module, ctxt->layers[i].module_ctxt, ticks, fragment);
+ }
}
@@ -179,6 +228,21 @@ static char * compose_random_layers_setting(void)
static int compose_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup)
{
const char *layers;
+ const char *texture;
+ const char *texture_values[] = {
+ "none",
+ "blinds",
+ "checkers",
+ "drizzle",
+ "julia",
+ "plasma",
+ "roto",
+ "stars",
+ "submit",
+ "swab",
+ "voronoi",
+ NULL
+ };
int r;
r = til_settings_get_and_describe_value(settings,
@@ -195,6 +259,20 @@ static int compose_setup(const til_settings_t *settings, til_setting_t **res_set
if (r)
return r;
+ r = til_settings_get_and_describe_value(settings,
+ &(til_setting_desc_t){
+ .name = "Module to use for source texture, \"none\" to disable",
+ .key = "texture",
+ .preferred = texture_values[0],
+ .annotations = NULL,
+ .values = texture_values,
+ },
+ &texture,
+ res_setting,
+ res_desc);
+ if (r)
+ return r;
+
/* turn layers colon-separated list into a null-terminated array of strings */
if (res_setup) {
compose_setup_t *setup;
@@ -257,6 +335,24 @@ static int compose_setup(const til_settings_t *settings, til_setting_t **res_set
setup = new;
} while (layer = strtok(NULL, ":"));
+ if (strcasecmp(texture, "none")) {
+ const til_module_t *texture_module;
+
+ texture_module = til_lookup_module(texture);
+ if (!texture_module) {
+ til_setup_free(&setup->til_setup);
+
+ return -EINVAL;
+ }
+
+ setup->texture = strdup(texture);
+ if (!setup->texture) {
+ til_setup_free(&setup->til_setup);
+
+ return -ENOMEM;
+ }
+ }
+
*res_setup = &setup->til_setup;
}
diff --git a/src/modules/montage/montage.c b/src/modules/montage/montage.c
index 8444616..65aabe6 100644
--- a/src/modules/montage/montage.c
+++ b/src/modules/montage/montage.c
@@ -141,17 +141,20 @@ static int montage_fragment_tile(const til_fb_fragment_t *fragment, unsigned til
xoff = x * tile_width;
yoff = y * tile_height;
- res_fragment->buf = fragment->buf + (yoff * fragment->pitch) + xoff;
- res_fragment->x = 0; /* fragment is a new frame */
- res_fragment->y = 0; /* fragment is a new frame */
- res_fragment->width = MIN(fragment->width - xoff, tile_width);
- res_fragment->height = MIN(fragment->height - yoff, tile_height);
- res_fragment->frame_width = res_fragment->width; /* fragment is a new frame */
- res_fragment->frame_height = res_fragment->height; /* fragment is a new frame */
- res_fragment->stride = fragment->stride + (fragment->width - res_fragment->width);
- res_fragment->pitch = fragment->pitch;
- res_fragment->number = number;
- res_fragment->cleared = fragment->cleared;
+ *res_fragment = (til_fb_fragment_t){
+ .texture = fragment->texture,
+ .buf = fragment->buf + (yoff * fragment->pitch) + xoff,
+ .x = 0, /* fragment is a new frame */
+ .y = 0, /* fragment is a new frame */
+ .width = MIN(fragment->width - xoff, tile_width),
+ .height = MIN(fragment->height - yoff, tile_height),
+ .frame_width = MIN(fragment->width - xoff, tile_width), /* fragment is a new frame */
+ .frame_height = MIN(fragment->height - yoff, tile_height), /* fragment is a new frame */
+ .stride = fragment->stride + (fragment->width - MIN(fragment->width - xoff, tile_width)),
+ .pitch = fragment->pitch,
+ .number = number,
+ .cleared = fragment->cleared,
+ };
return 1;
}
diff --git a/src/sdl_fb.c b/src/sdl_fb.c
index 249d746..b260091 100644
--- a/src/sdl_fb.c
+++ b/src/sdl_fb.c
@@ -202,13 +202,15 @@ static void * sdl_fb_page_alloc(til_fb_t *fb, void *context, til_fb_page_t *res_
/* rototiller wants to assume all pixels to be 32-bit aligned, so prevent unaligning pitches */
assert(!(p->surface->pitch & 0x3));
- res_page->fragment.buf = p->surface->pixels;
- res_page->fragment.width = c->width;
- res_page->fragment.frame_width = c->width;
- res_page->fragment.height = c->height;
- res_page->fragment.frame_height = c->height;
- res_page->fragment.pitch = p->surface->pitch >> 2;
- res_page->fragment.stride = res_page->fragment.pitch - c->width;
+ *res_page = (til_fb_page_t){
+ .fragment.buf = p->surface->pixels,
+ .fragment.width = c->width,
+ .fragment.frame_width = c->width,
+ .fragment.height = c->height,
+ .fragment.frame_height = c->height,
+ .fragment.pitch = p->surface->pitch >> 2,
+ .fragment.stride = (p->surface->pitch >> 2) - c->width,
+ };
return p;
}
diff --git a/src/til_fb.c b/src/til_fb.c
index eb14e27..f6a71a8 100644
--- a/src/til_fb.c
+++ b/src/til_fb.c
@@ -399,17 +399,20 @@ int til_fb_fragment_slice_single(const til_fb_fragment_t *fragment, unsigned n_f
if (yoff >= fragment->height)
return 0;
- res_fragment->buf = fragment->buf + yoff * fragment->pitch;
- res_fragment->x = fragment->x;
- res_fragment->y = yoff;
- res_fragment->width = fragment->width;
- res_fragment->height = MIN(fragment->height - yoff, slice);
- res_fragment->frame_width = fragment->frame_width;
- res_fragment->frame_height = fragment->frame_height;
- res_fragment->stride = fragment->stride;
- res_fragment->pitch = fragment->pitch;
- res_fragment->number = number;
- res_fragment->cleared = fragment->cleared;
+ *res_fragment = (til_fb_fragment_t){
+ .texture = fragment->texture,
+ .buf = fragment->buf + yoff * fragment->pitch,
+ .x = fragment->x,
+ .y = yoff,
+ .width = fragment->width,
+ .height = MIN(fragment->height - yoff, slice),
+ .frame_width = fragment->frame_width,
+ .frame_height = fragment->frame_height,
+ .stride = fragment->stride,
+ .pitch = fragment->pitch,
+ .number = number,
+ .cleared = fragment->cleared,
+ };
return 1;
}
@@ -435,17 +438,20 @@ int til_fb_fragment_tile_single(const til_fb_fragment_t *fragment, unsigned tile
xoff = x * tile_size;
yoff = y * tile_size;
- res_fragment->buf = fragment->buf + (yoff * fragment->pitch) + (xoff);
- res_fragment->x = fragment->x + xoff;
- res_fragment->y = fragment->y + yoff;
- res_fragment->width = MIN(fragment->width - xoff, tile_size);
- res_fragment->height = MIN(fragment->height - yoff, tile_size);
- res_fragment->frame_width = fragment->frame_width;
- res_fragment->frame_height = fragment->frame_height;
- res_fragment->stride = fragment->stride + (fragment->width - res_fragment->width);
- res_fragment->pitch = fragment->pitch;
- res_fragment->number = number;
- res_fragment->cleared = fragment->cleared;
+ *res_fragment = (til_fb_fragment_t){
+ .texture = fragment->texture,
+ .buf = fragment->buf + (yoff * fragment->pitch) + (xoff),
+ .x = fragment->x + xoff,
+ .y = fragment->y + yoff,
+ .width = MIN(fragment->width - xoff, tile_size),
+ .height = MIN(fragment->height - yoff, tile_size),
+ .frame_width = fragment->frame_width,
+ .frame_height = fragment->frame_height,
+ .stride = fragment->stride + (fragment->width - MIN(fragment->width - xoff, tile_size)),
+ .pitch = fragment->pitch,
+ .number = number,
+ .cleared = fragment->cleared,
+ };
return 1;
}
diff --git a/src/til_fb.h b/src/til_fb.h
index 55e9b6c..3ebede7 100644
--- a/src/til_fb.h
+++ b/src/til_fb.h
@@ -1,26 +1,31 @@
#ifndef _TIL_FB_H
#define _TIL_FB_H
+#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "til_settings.h"
#include "til_setup.h"
+#include "til_util.h"
+
+typedef struct til_fb_fragment_t til_fb_fragment_t;
/* All renderers should target fb_fragment_t, which may or may not represent
* a full-screen mmap. Helpers are provided for subdividing fragments for
* concurrent renderers.
*/
typedef struct til_fb_fragment_t {
- uint32_t *buf; /* pointer to the first pixel in the fragment */
- unsigned x, y; /* absolute coordinates of the upper left corner of this fragment */
- unsigned width, height; /* width and height of this fragment */
- unsigned frame_width; /* width of the frame this fragment is part of */
- unsigned frame_height; /* height of the frame this fragment is part of */
- unsigned stride; /* number of 32-bit words from the end of one row to the start of the next */
- unsigned pitch; /* number of 32-bit words separating y from y + 1, including any padding */
- unsigned number; /* this fragment's number as produced by fragmenting */
- unsigned cleared:1; /* if this fragment has been cleared since last flip */
+ til_fb_fragment_t *texture; /* optional source texture when drawing to this fragment */
+ uint32_t *buf; /* pointer to the first pixel in the fragment */
+ unsigned x, y; /* absolute coordinates of the upper left corner of this fragment */
+ unsigned width, height; /* width and height of this fragment */
+ unsigned frame_width; /* width of the frame this fragment is part of */
+ unsigned frame_height; /* height of the frame this fragment is part of */
+ unsigned stride; /* number of 32-bit words from the end of one row to the start of the next */
+ unsigned pitch; /* number of 32-bit words separating y from y + 1, including any padding */
+ unsigned number; /* this fragment's number as produced by fragmenting */
+ unsigned cleared:1; /* if this fragment has been cleared since last flip */
} til_fb_fragment_t;
/* This is a page handle object for page flip submission/life-cycle.
@@ -70,12 +75,20 @@ static inline int til_fb_fragment_contains(til_fb_fragment_t *fragment, int x, i
}
+/* gets a pixel from the fragment, no bounds checking is performed. */
+static inline uint32_t til_fb_fragment_get_pixel_unchecked(til_fb_fragment_t *fragment, int x, int y)
+{
+ return fragment->buf[(y - fragment->y) * fragment->pitch + x - fragment->x];
+}
+
+
/* puts a pixel into the fragment, no bounds checking is performed. */
static inline void til_fb_fragment_put_pixel_unchecked(til_fb_fragment_t *fragment, int x, int y, uint32_t pixel)
{
- uint32_t *pixels = fragment->buf + (y - fragment->y) * fragment->pitch;
+ if (fragment->texture)
+ pixel = til_fb_fragment_get_pixel_unchecked(fragment->texture, x, y);
- pixels[x - fragment->x] = pixel;
+ fragment->buf[(y - fragment->y) * fragment->pitch + x - fragment->x] = pixel;
}
@@ -91,8 +104,31 @@ static inline int til_fb_fragment_put_pixel_checked(til_fb_fragment_t *fragment,
}
-/* fill a fragment with an arbitrary pixel */
-static inline void til_fb_fragment_fill(til_fb_fragment_t *fragment, uint32_t pixel)
+/* copy a fragment, x,y,width,height are absolute coordinates within the frames, and will be clipped to the overlapping fragment areas */
+static inline void til_fb_fragment_copy(til_fb_fragment_t *dest, int x, int y, int width, int height, til_fb_fragment_t *src)
+{
+ int X = MAX(dest->x, src->x);
+ int Y = MAX(dest->y, src->y);
+ int W = MIN(dest->x + dest->width, src->x + src->width) - X;
+ int H = MIN(dest->y + dest->height, src->y + src->height) - Y;
+
+ assert(W >= 0 && H >= 0);
+
+ /* XXX FIXME TODO */
+ /* XXX FIXME TODO */
+ /* XXX FIXME TODO */
+ /* this is PoC fast and nasty code, optimize this to at least bulk copy rows of pixels */
+ /* XXX FIXME TODO */
+ /* XXX FIXME TODO */
+ /* XXX FIXME TODO */
+ for (int v = 0; v < H; v++) {
+ for (int u = 0; u < W; u++)
+ til_fb_fragment_put_pixel_unchecked(dest, X + u, Y + v, til_fb_fragment_get_pixel_unchecked(src, X + u, Y + v));
+ }
+}
+
+
+static inline void _til_fb_fragment_fill(til_fb_fragment_t *fragment, uint32_t pixel)
{
uint32_t *buf = fragment->buf;
@@ -105,13 +141,24 @@ static inline void til_fb_fragment_fill(til_fb_fragment_t *fragment, uint32_t pi
}
+/* fill a fragment with an arbitrary pixel */
+static inline void til_fb_fragment_fill(til_fb_fragment_t *fragment, uint32_t pixel)
+{
+ if (!fragment->texture)
+ return _til_fb_fragment_fill(fragment, pixel);
+
+ /* when a texture is present, pixel is ignored and instead sourced from fragment->texture->buf[y*pitch+x] */
+ til_fb_fragment_copy(fragment, fragment->x, fragment->y, fragment->width, fragment->height, fragment->texture);
+}
+
+
/* clear a fragment */
static inline void til_fb_fragment_clear(til_fb_fragment_t *fragment)
{
if (fragment->cleared)
return;
- til_fb_fragment_fill(fragment, 0);
+ _til_fb_fragment_fill(fragment, 0);
fragment->cleared = 1;
}
© All Rights Reserved