diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2022-09-04 23:13:36 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2022-09-04 23:13:36 -0700 |
commit | b5a2667f6c94d5a275251bf6cc359480100a651c (patch) | |
tree | e68c50d4503a0a063894251b055b4a9a7e6a6713 | |
parent | 7d174878cc27b1319c246913e71cf6ab8fefcb31 (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.c | 29 | ||||
-rw-r--r-- | src/modules/montage/montage.c | 28 | ||||
-rw-r--r-- | src/til.c | 5 | ||||
-rw-r--r-- | src/til_fb.c | 58 | ||||
-rw-r--r-- | src/til_threads.c | 12 |
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 */ @@ -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); |