summaryrefslogtreecommitdiff
path: root/src
AgeCommit message (Collapse)Author
2022-06-13modules/sparkler: plug longstanding chunker leakVito Caputo
Once upon a time this thing asserted the pinned chunks were empty, and that code is still sitting there commented out. But when it was commented out ages ago, to enable bulk freeing of chunkers without requiring unrefs of every allocation as an optimization, no code was added to free the pinned chunks. It's been easily ignored all this time since nobody really runs rototiller long enough to notice, but that's becoming less true now with how interesting something like: --module=rtv,layers=compose,duration=1,context_duration=1,snow_module=none is becoming... There are other leaks still, largely surrounding settings, but they are quite small. Eventually those will get tidied up as well.
2022-06-10modules/checkers: experimenting with fill modesVito Caputo
this introduces a color= setting syntax: color=#rrggbb color=0xrrggbb color=rrggbb where rrggbb is case-insensitive html-style hexadecimal also introduces a fill= setting: fill=color fill=sampled fill=textured fill=random fill=mixed sampled draws the color from the incoming fragment when layered, textured draws the pixels from the texture when available, random randomizes the choice from color,sampled,textured. mixed isn't implemented fully and is just aliased to random currently. The thinking for mixed is to allow specifying proportions for color,sampled,textured which would then be applied as weights when randomizing the selection from the three at every filled checker. the current implementation is just calling rand() when randomized, but should really be like the other dynamics in checkers with rate control and hash-based. and introduces a fill_module= setting: this is a first stab at employing other modules for filling the filled cells. Note since checkers is already a threaded module, the fill module context gets created per-cpu but with an n_cpus=1. This is kind of the first time module contexts are being rendered manifold for the same frame, and that's illuminating some shortcomings which needed to be dealt with. Some modules automatically advance a phase/T value on every render which gets persisted in their context struct. With how checkers is using contexts, it's desirable for multiple renders of the same context using the same ticks to produce the same output. So modules need to be more careful about time and determine "dt" (delta-time) values, and animate proportional to ticks elapsed. When ticks doesn't change between renders, dt is zero, and nothing should change. For now this is using a hard-coded list of modules to choose from, you specify the module by name or "none" for no fill_module (solid checker fill). ex: "fill_module=shapes" There's a need for something like fragment color and flag overrides to allow til_module_render() to be treated as more of a brush where the caller gets to specify what colors to use, or if texturing should be allowed. For now, when fill_module=$module is employed, the color determination stuff within checkers doesn't get applied. That will need to be fixed in the future.
2022-06-10til: introduce til_frame_plan_t and .cpu_affinityVito Caputo
modules/checkers w/fill_module=$module requires a consistent mapping of cpu to fragnum since it creates a per-cpu til_module_context_t for the fill_module. The existing implementation for threaded rendering maximizes performance by letting *any* scheduled to run thread advance fragnum atomically and render the acquired fragnum indiscriminately. A side effect of this is any given frame, even rendered by the same module, will have a random mapping of cpus/threads to fragnums. With this change, the simple til_module_t.prepare_frame() API of returning a bare fragmenter function is changed to instead return a "frame plan" in til_frame_plan_t. Right now til_frame_plan_t just contains the same fragmenter as before, but also has a .cpu_affinity member for setting if the frame requires a stable relationship of cpu/thread to fragnum. Setting .cpu_affinity should be avoided if unnecessary, and that is the default if you don't mention .cpu_affinity at all when initializing the plan in the ergonomic manner w/designated initializers. This is because the way .cpu_affinity is implemented will leave threads spinning while they poll for *their* next fragnum using atomic intrinsics. There's probably some room for improvement here, but this is good enough for now to get things working and correct.
2022-06-10modules/roto: drive from ticks, move palette to contetxtVito Caputo
The palette mutates across frames, on a context-specific schedule. Meaning the palette is per-context, so move it into roto_context_t. The phase also needs to be driven by ticks. And when ticks doesn't change in cases where the same context is rendered manifold in the same frame, the phase shouldn't move.
2022-06-10modules/plato: derive movement from delta ticksVito Caputo
This way if a given context gets rendered repeatedly for the same tick, no movement occurs, until ticks changes.
2022-06-10til: add ticks to til_module_context_tVito Caputo
Also wire this up to the til_module_context_new() helper and all its callers. This is in preparation for modules doing more correct delta-T derived animation.
2022-06-10til_threads: remove vestigial n_fragments counterVito Caputo
This is leftover from 4e5286 which was mostly removed when frame zeroing was simplified, but for some reason this was missed. Just get rid of the count as it's not used.
2022-06-10modules/blinds: use til_fb_put_pixel_checked()Vito Caputo
While testing an experimental checkers w/fill_module=blinds with ASAN it became clear this module is making flawed assumptions about fragment->frame_{width,height} and fragment->{width,height} being equal. When used by checkers for filling cells, there are situations where the edge cell fragments need to describe a frame slightly larger than the drawn area, because the cell size doesn't align perfectly to the overall window/screen dimensions. So in these cases the synthesized frame will still be a full cell's dimensions while the width,height serve to clip within that area. If modules aren't properly clipping their rendering, instead just using frame_{width,height}, then they will have to use the _checked() variants to ensure clipping occurs properly on a per-pixel (slower) basis.
2022-06-10modules/montage: minor fixupsVito Caputo
Contexts aren't void* anymore, and free the contexts array too on failure.
2022-06-10modules/montage: remove vestigial unused variableVito Caputo
This initializer could perform an out-of-bounds read since it occurs before the n_modules bounds check. Since the variable isn't even being used anymore just get rid of this. Also found via ASAN.
2022-06-10modules/pixbounce: use til_fb_put_pixel_checked()Vito Caputo
While testing a checkers change that fills cells using other modules, ASAN kept tripping on pixbounce: ==147817==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7fc78a31c10c at pc 0x55b30cd406e2 bp 0x7fc790afd0d0 sp 0x7fc790afd0c8 WRITE of size 4 at 0x7fc78a31c10c thread T2 #0 0x55b30cd406e1 in til_fb_fragment_put_pixel_unchecked pixbounce.c #1 0x55b30cd3f8ae in pixbounce_render_fragment pixbounce.c #2 0x55b30cd1dffb in module_render_fragment til.c #3 0x55b30cd1d989 in til_module_render (/home/foo/src/rototiller/build/src/rototiller+0x134989) #4 0x55b30cd22534 in checkers_render_fragment checkers.c #5 0x55b30cd14681 in thread_func til_threads.c #6 0x7fc792b3d5c1 in start_thread pthread_create.c #7 0x7fc792bc2583 in __clone (/usr/lib/libc.so.6+0x112583) 0x7fc78a31c10c is located 2276 bytes to the right of 1228840-byte region [0x7fc78a1ef800,0x7fc78a31b828) allocated by thread T0 here: #0 0x55b30cccf219 in __interceptor_malloc (/home/foo/src/rototiller/build/src/rototiller+0xe6219) #1 0x7fc792d0e528 (/usr/lib/libSDL2-2.0.so.0+0x39528) Thread T2 created by T0 here: #0 0x55b30cc3cfa8 in pthread_create (/home/foo/src/rototiller/build/src/rototiller+0x53fa8) #1 0x55b30cd13fff in til_threads_create (/home/foo/src/rototiller/build/src/rototiller+0x12afff) #2 0x55b30cd1d573 in til_init (/home/foo/src/rototiller/build/src/rototiller+0x134573) #3 0x55b30cd08f6c in main (/home/foo/src/rototiller/build/src/rototiller+0x11ff6c) #4 0x7fc792add30f in __libc_start_call_main libc-start.c SUMMARY: AddressSanitizer: heap-buffer-overflow pixbounce.c in til_fb_fragment_put_pixel_unchecked Shadow bytes around the buggy address: 0x0ff97145b7d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0ff97145b7e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0ff97145b7f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0ff97145b800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0ff97145b810: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0ff97145b820: fa[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0ff97145b830: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0ff97145b840: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0ff97145b850: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0ff97145b860: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0ff97145b870: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==147817==ABORTING --- Rather than spend time digging into pixbounce's arithmetic, just using the checked variant for now.
2022-06-07modules/moire: implement rudimentary moire moduleVito Caputo
This introduces a very naive unoptimized moire interference pattern module, it's rather slow complete with a sqrtf() per pixel per center.
2022-05-29*: pivot to til_module_context_tVito Caputo
- modules now allocate their contexts using til_module_context_new() instead of [cm]alloc(). - modules simply embed til_module_context_t at the start of their respective private context structs, if they do anything with contexts - modules that do nothing with contexts (lack a create_context() method), will now *always* get a til_module_context_t supplied to their other methods regardless of their create_context() presence. So even if you don't have a create_context(), your prepare_frame() and/or render_fragment() methods can still access seed and n_cpus from within the til_module_context_t passed in as context, *always*. - modules that *do* have a create_context() method, implying they have their own private context type, will have to cast the til_module_context_t supplied to the other methods to their private context type. By embedding the til_module_context_t at the *start* of their private context struct, a simple cast is all that's needed. If it's placed somewhere else, more annoying container_of() style macros are needed - this is strongly discouraged, just put it at the start of struct. - til_module_create_context() now takes n_cpus, which may be set to 0 for automatically assigning the number of threads in its place. Any non-zero value is treated as an explicit n_cpus, primarily intended for setting it to 1 for single-threaded contexts necessary when embedded within an already-threaded composite module. - modules like montage which open-coded a single-threaded render are now using the same til_module_render_fragment() as everything else, since til_module_create_context() is accepting n_cpus. - til_module_create_context() now produces a real type, not void *, that is til_module_context_t *. All the other module context functions now operate on this type, and since til_module_context_t.module tracks the module this context relates to, those functions no longer require both the module and context be passed in. This is especially helpful for compositing modules which do a lot of module context creation and destruction; the module handle is now only needed to create the contexts. Everything else operating on that context only needs the single context pointer, not module+context pairs, which was unnecessarily annoying. - if your module's context can be destroyed with a simple free(), without any deeper knowledge or freeing of nested pointers, you can now simply omit destroy_context() altogether. When destroy_context() is missing, til_module_context_free() will automatically use libc's free() on the pointer returned from your create_context() (or on the pointer that was automatically created if you omitted create_context() too, for the bare til_module_context_t that got created on your behalf anyways). For the most part, these changes don't affect module creation. In some ways this eases module creation by making it more convenient access seed and n_cpus if you had no further requirement for a context struct. In other ways it's slightly annoying to have to do type-casts when you're working with your own context type, since before it was all void* and didn't require casts when assigning to your typed context variables. The elimination for requiring a destroy_context() method in simple free() of private context scenarios removes some boilerplate in simple cases. I think it's a wash for module writers, or maybe a slight win for the simple cases.
2022-05-29til: introduce til_module_context_tVito Caputo
Preparatory commit for embedding a til type in the module contexts, similar to til_setup_t for the module setups. This will provide a convenient way to embed seed and n_cpus in every module context, without having to implement that yourself. But it also makes it so modules with no need for a context can continue not implementing those methods, without obstructing libtil from transparently doing it anyways with a bare til_module_context_t. This is kind of important as the current architecture made it difficult to do things like create contexts with explicit n_cpus, like in composite/meta modules which are already threaded and wish to run embedded modules with n_cpus=1. With this addition, n_cpus could be specified at context create time, and it will always become remembered in the til_module_context_t regardless of what the module implements. That way it can definitely be carried into the prepare/render methods, with no opportunity for disconnect between what was passed to context create and what goes to the render methods. Nothing is functionally changed in this commit alone, subsequent commits will actually make use of it and realize what I've said above.
2022-05-25setup: return the desc for failed setting on errorVito Caputo
This commit improves the error printed when cli-supplied args fail, adding at least the key name to what used to be just a stringified errno: ``` $ src/rototiller --module=shapes,scale=99 Shape type: 0: circle 1: pinwheel 2: rhombus 3: star Enter a value 0-3 [1 (pinwheel)]: Fatal error: unable to use args for setting "scale": Invalid argument $ ```
2022-05-25til: mention --go in --helpVito Caputo
Forgot to add this when adding --go
2022-05-25til: add --go to supported argsVito Caputo
In rototiller this disables the automatic displaying of settings actually used when they differ from what was explicitly specified as args. Which also disables the waiting to press a key. This should also get used by glimmer to automatically start rendering without just putting up the configured settings panel and waiting for a click on "go!".
2022-05-25*: normalize on all case-insensitive comparisonsVito Caputo
I don't think rototiller is an appropriate place for being so uncooperative, if someone gets the case wrong anywhere just make it work. We should avoid making different things so subtly different that case alone is the distinction anyways, so I don't see this creating any future namespace collision problems.
2022-05-25modules/shapes: update TODO commentVito Caputo
A bunch of these have just been done
2022-05-25modules/shapes: slow spins down a bitVito Caputo
I didn't like the too fast spins where you can't even really get a read on what's going on in the shape. Suspect this will get tweaked more in the future...
2022-05-25modules/shapes: introduce pinch settingVito Caputo
This is kind of experimental, not sure how I feel about it. pinch=0..1 with a bunch of fractions, 0 disables it. pinch_spin=-1..1 same as spin= pinches=1..10 number of pinches, which come in pairs This applies to all the current shapes, for a tour: --module=rtv,channels=shapes,duration=2,context_duration=2,snow_module=none --defaults I think the speeds might go to high atm, I kind of liked the slower spins before all this more.
2022-05-24modules/shapes: fixup indentation of star+pinwheelVito Caputo
woops
2022-05-24modules/shapes: add scale settingVito Caputo
scale=1-.5 with a few other fractions in between Mostly added for the sake of rtv/compose where modules currently always go full-frame, which can be really annoying sometimes for shapes without any variety in the scale. When checkers starts filling cells using modules like shapes, it'll be interesting to see how this fares there since it'll probably be randomizing the settings too. At least floored at 50% should still produce something legible in /most/ of the checkers cell sizes. Definitely won't look like anything in the smaller end of the checkers sizes though... hrm.
2022-05-24modules/shapes: add spin setting for star+pinwheelVito Caputo
Introduces spin={-1,0,1} with a few intermediate fractions on both sides of 0. Controls rate and direction. As-is these multiple choice style options don't let you explicitly set a value in rototiller on the commandline that isn't in the set. There should probably be a flag in the desc we can set when bypassing the available options is tolerable, probably when regex's start getting enforced. That way rototiller's commandline setting parsing can just lean on the regex, and if the desc says anything can come in that passes the regex even if it's not in the values set, this can all still work and have something resembling input validation. At the end of the day, the multiple choice value sets are supposed to be a convenience/guide to a sane variety of values and of particular utility to randomizers like used by rtv/montage/compose, but also GUI setting selectors like in glimmer. They're not intended to get in the way preventing development from accessing explicit values of arbitrary precision which can be really necessary especially when trying to determine what's best for going in the values set.
2022-05-24modules/shapes: add points setting for star+pinwheelVito Caputo
Replace the hard-coded 5 points with a points=3-20 setting Nothing fancy going on here
2022-05-23*: silence some more clang parens warningsVito Caputo
2022-05-23modules/shapes: various small fixupsVito Caputo
- clear padding when {letter,pillar}boxed - limit costly rendering to shape size area when boxed - fix <= inclusion tests in circle and rhombus: s/<=/</
2022-05-23modules/compose: don't clear frame in prepare_frame()Vito Caputo
I'm not sure why this was being done, it was probably just vestigial from whatever I bootstrapped the compose module with and never thought to remove it. The first compose layer rendered will clear the frame if necessary. By compose doing it ahead of time, it's performing potentially unnecessary work clearing if the first layer is a frame-filler style render where no clear is ever performed.
2022-05-23til: simplify fragment->cleared maintenanceVito Caputo
Just assume a fragment has been logically cleared after til_module_render() has done all its potential steps. I'm not certain this doesn't break some existing assumptions WRT fragmented/threaded clears and their propagation out to the outer frame. But I've been operating under the assumption that this was already happening in terms of an implicit setting of til_fb_fragment_t.cleared after a module's render happened. Except I don't see anything in the existing code or history actually doing that, which is odd. For modules that don't invoke til_fb_fragment_clear() explicitly because they are frame-fillers (think submit, swab, ray, julia, plasma, these are all full-frame renders that don't benefit from pre-clearing), they weren't leaving fragment->cleared set, despite having fully initialized the frame's contents. We should be able to just assume after prepare/render/finish has happened for a given module, the target fragment has been cleared. Commit 4e5286 had introduced somewhat complicated .cleared maintenance and propagation for threaded renders, but when we just treat all finished module renders into a given fragment as logically clearing the fragment we can just skip all that.
2022-05-21modules/*: first stab at utilizing supplied seedsVito Caputo
This is a mostly mechanical change of using rand_r() in place of rand(), using the provided seed as the seed state. There's some outstanding rand()s outside of create_context() which should probably get switched over, with the seed being stowed in the context struct. I didn't bother going deeper on this at the moment in the interests of getting to sleep soon.
2022-05-21modules/voronoi: silence warning about fmt mismatchVito Caputo
n_cells is a size_t, use %zu clang complained, gcc doesn't, huh
2022-05-21til: supply a seed to til_module_t.create_context()Vito Caputo
In the recent surge of ADD-style rtv+compose focused development, a bunch of modules were changed to randomize initial states at context_create() so they wouldn't be so repetitive. But the way this was done in a way that made it impossible to suppress the randomized initial state, which sometimes may be desirable in compositions. Imagine for instance something like the checkers module, rendering one module in the odd cells, and another module into the even cells. Imagine if these modules are actually the same, but if checkers used one seed for all the odd cells and another seed for all the even cells. If the modules used actually utilized the seed provided, checkers would be able to differentiate the odd from even by seeding them differently even when the modules are the same. This commit is a step in that direction, but rototiller and all the composite modules (rtv,compose,montage) are simply passing rand() as the seeds. Also none of the modules have yet been modified to actually make use of these seeds. Subsequent commits will update modules to seed their pseudo-randomized initial state from the seed value rather than always calling things like rand() themselves.
2022-05-21modules/shapes: add procedural 2D shapes moduleVito Caputo
Mostly for compositing purposes, here will be a corpus of 2D shapes, parameterized/procedurally generated and able to rotate and perhaps have other dynamics added. What shapes are there presently I had started implementing in checkers as "styles", before realizing they really should just be a separate module checkers can call into. Not terribly interesting by itself, but as blinds and checkers demonstrated, these things deliver a lot of value in compositional situations. They're creating the palette to draw from.
2022-05-06modules/pixbounce: add Ignignokt & Err pixmapsPhilip J Freeman
2022-05-06modules/pixbounce: add "rototiller" qr codePhilip J Freeman
2022-05-06modules/pixbounce: add setting for pixmap choicePhilip J Freeman
2022-05-06modules/pixbounce: remove weird pixmapsPhilip J Freeman
2022-05-06modules/pixbounce: add setting for pixmap sizePhilip J Freeman
2022-05-06modules/pixbounce: support arbitrary pixmap sizePhilip J Freeman
2022-05-03modules/voronoi: slightly underscale to prevent OOB accessVito Caputo
We don't actually want to produce indices 0-width and 0-height
2022-05-02modules/rtv: silence compiler warning about parensVito Caputo
2022-05-02modules/rtv: plug big channel leak on context destroyVito Caputo
There's more to cleanup in rtv destruction, but this is the major one.
2022-05-02modules/submit: fix bilerp mode out-of-bounds accessVito Caputo
Found via -fsanitize=address, this is a quick and dirty way to prevent the OOB access without adding more conditionals, just prevent scaling the fragment dimensions to the full grid dimensions. This could be done better by reworking things a bit and putting zero at the center of the grid with a -1..+1 mapping, so rounding towards zero would land in the middle as opposed to off the start, with the existing .5f offset. But for now just fix the bug, nobody will notice the slight LCD overscan-style difference of bilerp=on vs. off due to this way.
2022-05-02modules/montage: fix fragnum misuse as cpu #Vito Caputo
This was causing the snow module to scribble via montage, since snow uses per-cpu rand seeds indexed using the cpu value. I didn't dig in to see if this was a vestigial thing where fragnum once was passed as a parameter (it's also in til_fb_fragment_t.number, but probably wasn't always that way). But it's now used as a cpu idx, but since they're the same type nothing complained, they say programming is hard.
2022-05-01modules/rtv: make "compose" the default channelVito Caputo
Also shortened the durations across the board, and defaulted snow to "none". With "compose" being another meta module, and the randomized settings, this actually gives a more interesting grand tour of everything possible.
2022-05-01til_fb: add draw flags for controlling texturabilityVito Caputo
Just adds TIL_FB_DRAW_FLAG_TEXTURABLE so callers can granularly inhibit texturing if desired.
2022-05-01til_fb: introduce a fragment texture sourceVito Caputo
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.
2022-05-01modules/julia: randomize initial stateVito Caputo
Same as for roto and plasma...
2022-05-01modules/plasma: randomize initial state of contextsVito Caputo
As with roto, it's important to differentiate plasma instances when layered... plus it's kind of boring to always start plasma identically.
2022-05-01modules/roto: randomize roto initial stateVito Caputo
Just something quick and dirty to differentiate roto layers, plus it's kind of boring having roto always start at the same state.
© All Rights Reserved