summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2022-09-04 23:13:36 -0700
committerVito Caputo <vcaputo@pengaru.com>2022-09-04 23:13:36 -0700
commitb5a2667f6c94d5a275251bf6cc359480100a651c (patch)
treee68c50d4503a0a063894251b055b4a9a7e6a6713
parent7d174878cc27b1319c246913e71cf6ab8fefcb31 (diff)
til: fixup til_fb_fragment_t.texture fragmenting
Until now when fragmenting with a texture present the texture pointer was simply copied through to the new logical fragment. The problem with that is when sampling pixels from the texture in a nested frame scenario, the locations didn't align with the placement of the logical fragment. With this change when the incoming fragment has a texture, the output fragment gets some uninitialized memory attached in the outgoing fragment's texture pointer. Then the fragmenter is expected to do the same populating of res_fragment->texture it already did for res_fragment, just relative to fragment->texture->{buf,stride,pitch} etc. It's a bit hairy/janky because til_fb_fragment_t.texture is just a pointer to another til_fb_fragment_t. So the ephemeral/logical fragments fragmenting/tiling produces which tend to just be sitting on the stack need to get another til_fb_fragment_t instance somewhere and made available at the ephemeral til_fb_fragment_t's .texture member. We don't want to be allocating and freeing these things constantly, so for now I'm just ad-hoc stowing the pointer of an adjacent on-stack texture fragment in the .texture member when the incoming fragment has a texture. But this is gross because the rest of the fragment contents don't get initialized _at_all_, and currently if the incoming fragment has no texture the res_fragment->texture member isn't even initialized. The fragmenters aren't really supposed to be expecting anything sensible in *res_fragment, but now we're making use of res_fragment->texture *if* fragment->texture is set. This is just gross. So there's a bunch of asserts sprinkled around to help police this fragility for now, but if someone writes new fragmenters there's a good chance this will trip them up.
-rw-r--r--src/modules/checkers/checkers.c29
-rw-r--r--src/modules/montage/montage.c28
-rw-r--r--src/til.c5
-rw-r--r--src/til_fb.c58
-rw-r--r--src/til_threads.c12
5 files changed, 125 insertions, 7 deletions
diff --git a/src/modules/checkers/checkers.c b/src/modules/checkers/checkers.c
index 32b5aa3..9dcc05c 100644
--- a/src/modules/checkers/checkers.c
+++ b/src/modules/checkers/checkers.c
@@ -146,6 +146,9 @@ int checkers_fragment_tile_single(const til_fb_fragment_t *fragment, unsigned ti
unsigned tiled_w = w * tile_size, tiled_h = h * tile_size;
unsigned x, y, xoff, yoff, xshift = 0, yshift = 0;
+ assert(fragment);
+ assert(res_fragment);
+
/* Detect the need for fractional tiles on both axis and shift the fragments
* to keep the overall checkered output centered. This complicates res_fragment.{x,y,width,height}
* calculations for the peripheral checker tiles as those must clip when shifted.
@@ -171,8 +174,32 @@ int checkers_fragment_tile_single(const til_fb_fragment_t *fragment, unsigned ti
xoff = x * tile_size;
yoff = y * tile_size;
+ if (fragment->texture) {
+ assert(res_fragment->texture);
+ assert(fragment->frame_width == fragment->texture->frame_width);
+ assert(fragment->frame_height == fragment->texture->frame_height);
+ assert(fragment->width == fragment->texture->width);
+ assert(fragment->height == fragment->texture->height);
+ assert(fragment->x == fragment->texture->x);
+ assert(fragment->y == fragment->texture->y);
+
+ *(res_fragment->texture) = (til_fb_fragment_t){
+ .buf = fragment->texture->buf + (yoff * fragment->texture->pitch) - (y ? (yshift * fragment->texture->pitch) : 0) + (xoff - (x ? xshift : 0)),
+ .width = MIN(fragment->width - (xoff - xshift), x ? tile_size : (tile_size - xshift)),
+ .height = MIN(fragment->height - (yoff - yshift), y ? tile_size : (tile_size - yshift)),
+ .x = x ? 0 : xshift,
+ .y = y ? 0 : yshift,
+ .frame_width = tile_size,
+ .frame_height = tile_size,
+ .stride = fragment->texture->stride + (fragment->width - MIN(fragment->width - (xoff - xshift), x ? tile_size : (tile_size - xshift))),
+ .pitch = fragment->texture->pitch,
+ .cleared = fragment->texture->cleared,
+ };
+ }
+
*res_fragment = (til_fb_fragment_t){
- .texture = fragment->texture,
+ .texture = fragment->texture ? res_fragment->texture : NULL,
+ /* TODO: copy pasta! */
.buf = fragment->buf + (yoff * fragment->pitch) - (y ? (yshift * fragment->pitch) : 0) + (xoff - (x ? xshift : 0)),
.width = MIN(fragment->width - (xoff - xshift), x ? tile_size : (tile_size - xshift)),
.height = MIN(fragment->height - (yoff - yshift), y ? tile_size : (tile_size - yshift)),
diff --git a/src/modules/montage/montage.c b/src/modules/montage/montage.c
index eaf8be7..1191a60 100644
--- a/src/modules/montage/montage.c
+++ b/src/modules/montage/montage.c
@@ -120,6 +120,9 @@ static int montage_fragment_tile(const til_fb_fragment_t *fragment, unsigned til
unsigned w = fragment->width / tile_width, h = fragment->height / tile_height;
unsigned x, y, xoff, yoff;
+ assert(fragment);
+ assert(res_fragment);
+
#if 0
/* total coverage isn't important in montage, leave blank gaps */
/* I'm keeping this here for posterity though and to record a TODO:
@@ -142,8 +145,31 @@ static int montage_fragment_tile(const til_fb_fragment_t *fragment, unsigned til
xoff = x * tile_width;
yoff = y * tile_height;
+ if (fragment->texture) {
+ assert(res_fragment->texture);
+ assert(fragment->frame_width == fragment->texture->frame_width);
+ assert(fragment->frame_height == fragment->texture->frame_height);
+ assert(fragment->width == fragment->texture->width);
+ assert(fragment->height == fragment->texture->height);
+ assert(fragment->x == fragment->texture->x);
+ assert(fragment->y == fragment->texture->y);
+
+ *(res_fragment->texture) = (til_fb_fragment_t){
+ .buf = fragment->texture->buf + (yoff * fragment->texture->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->texture->stride + (fragment->width - MIN(fragment->width - xoff, tile_width)),
+ .pitch = fragment->texture->pitch,
+ .cleared = fragment->texture->cleared,
+ };
+ }
+
*res_fragment = (til_fb_fragment_t){
- .texture = fragment->texture,
+ .texture = fragment->texture ? res_fragment->texture : NULL,
.buf = fragment->buf + (yoff * fragment->pitch) + xoff,
.x = 0, /* fragment is a new frame */
.y = 0, /* fragment is a new frame */
diff --git a/src/til.c b/src/til.c
index 1bc03b4..151f690 100644
--- a/src/til.c
+++ b/src/til.c
@@ -189,7 +189,10 @@ static void module_render_fragment(til_module_context_t *context, til_threads_t
til_threads_wait_idle(threads);
} else {
unsigned fragnum = 0;
- til_fb_fragment_t frag, *frag_ptr = &frag;
+ til_fb_fragment_t frag, texture, *frag_ptr = &frag;
+
+ if ((*fragment_ptr)->texture)
+ frag.texture = &texture; /* fragmenter needs the space */
while (frame_plan.fragmenter(context, *fragment_ptr, fragnum++, &frag))
module->render_fragment(context, ticks, 0, &frag_ptr);
diff --git a/src/til_fb.c b/src/til_fb.c
index 99bf4d3..536a6f2 100644
--- a/src/til_fb.c
+++ b/src/til_fb.c
@@ -575,11 +575,38 @@ int til_fb_fragment_slice_single(const til_fb_fragment_t *fragment, unsigned n_f
unsigned slice = fragment->height / n_fragments;
unsigned yoff = slice * number;
+ assert(fragment);
+ assert(res_fragment);
+
if (yoff >= fragment->height)
return 0;
+ if (fragment->texture) {
+ assert(res_fragment->texture);
+ assert(fragment->frame_width == fragment->texture->frame_width);
+ assert(fragment->frame_height == fragment->texture->frame_height);
+ assert(fragment->width == fragment->texture->width);
+ assert(fragment->height == fragment->texture->height);
+ assert(fragment->x == fragment->texture->x);
+ assert(fragment->y == fragment->texture->y);
+
+ *(res_fragment->texture) = (til_fb_fragment_t){
+ .buf = fragment->texture->buf + yoff * fragment->texture->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->texture->stride,
+ .pitch = fragment->texture->pitch,
+ .cleared = fragment->texture->cleared,
+ };
+
+ }
+
*res_fragment = (til_fb_fragment_t){
- .texture = fragment->texture,
+ .texture = fragment->texture ? res_fragment->texture : NULL,
.buf = fragment->buf + yoff * fragment->pitch,
.x = fragment->x,
.y = yoff,
@@ -602,6 +629,9 @@ int til_fb_fragment_tile_single(const til_fb_fragment_t *fragment, unsigned tile
unsigned w = fragment->width / tile_size, h = fragment->height / tile_size;
unsigned x, y, xoff, yoff;
+ assert(fragment);
+ assert(res_fragment);
+
if (w * tile_size < fragment->width)
w++;
@@ -617,8 +647,32 @@ int til_fb_fragment_tile_single(const til_fb_fragment_t *fragment, unsigned tile
xoff = x * tile_size;
yoff = y * tile_size;
+ if (fragment->texture) {
+ assert(res_fragment->texture);
+ assert(fragment->frame_width == fragment->texture->frame_width);
+ assert(fragment->frame_height == fragment->texture->frame_height);
+ assert(fragment->width == fragment->texture->width);
+ assert(fragment->height == fragment->texture->height);
+ assert(fragment->x == fragment->texture->x);
+ assert(fragment->y == fragment->texture->y);
+
+ *(res_fragment->texture) = (til_fb_fragment_t){
+ .buf = fragment->texture->buf + (yoff * fragment->texture->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->texture->stride + (fragment->width - MIN(fragment->width - xoff, tile_size)),
+ .pitch = fragment->texture->pitch,
+ .cleared = fragment->texture->cleared,
+ };
+
+ }
+
*res_fragment = (til_fb_fragment_t){
- .texture = fragment->texture,
+ .texture = fragment->texture ? res_fragment->texture : NULL,
.buf = fragment->buf + (yoff * fragment->pitch) + (xoff),
.x = fragment->x + xoff,
.y = fragment->y + yoff,
diff --git a/src/til_threads.c b/src/til_threads.c
index e2c8a97..9e55a29 100644
--- a/src/til_threads.c
+++ b/src/til_threads.c
@@ -63,7 +63,11 @@ static void * thread_func(void *_thread)
* which may require a consistent mapping of CPU to fragnum across frames.
*/
for (;;) {
- til_fb_fragment_t frag, *frag_ptr = &frag;
+ til_fb_fragment_t texture, frag, *frag_ptr = &frag;
+
+ /* XXX: jank alert, need to cleanup texture integration TODO */
+ if ((*(threads->fragment_ptr))->texture)
+ frag.texture = &texture; /* provide space, but the fragmenter must populate it */
while (!__sync_bool_compare_and_swap(&threads->next_fragment, frag_num, frag_num + 1));
@@ -76,7 +80,11 @@ static void * thread_func(void *_thread)
} else { /* render *any* available fragment */
for (;;) {
unsigned frag_num;
- til_fb_fragment_t frag, *frag_ptr = &frag;
+ til_fb_fragment_t texture, frag, *frag_ptr = &frag;
+
+ /* XXX: jank alert, need to cleanup texture integration TODO */
+ if ((*(threads->fragment_ptr))->texture)
+ frag.texture = &texture; /* provide space, but the fragmenter must populate it */
frag_num = __sync_fetch_and_add(&threads->next_fragment, 1);
© All Rights Reserved