Age | Commit message (Collapse) | Author |
|
Preparatory commit for til_module_create_context() requiring
setups even when there's no til_module_t.setup() method.
This helper will produce the minimal til_setup_t in such cases,
or hand off the task to til_module_t.setup() when present.
Note the need for passing res_setting and res_desc to
til_module_t.setup() despite not being a settings-construction
scenario. This is because of how modules using nested settings
tend to use res_setting for storing the current setting in
accessing the nested instance, which must still occur even when
just baking the complete setup.
It's expected that any composite/meta modules utilizing other
modules will use this helper to produce the baked setups, instead
of the ad-hoc direct calling of til_module_t.setup() they do
presently.
|
|
Preparatory commit for deprecating til_module_context_t.path in
favor of mandatory til_module_context_t.setup providing the
settings-derived context path.
Future commit will drop til_module_context_t.{path,path_hash}
|
|
b9123bbb added describing incoming preexisting settings, but the
spec's returned values omitted experimental modules. This
resulted in breaking the ability to say things like --module=rkt
to access the experimental rkt module despite it not showing in
the interactive setup list of values.
This commit includes experimental modules in the spec's values
when being produced for a preexisting, undescribed setting.
Restoring one's ability to access experimental modules via the
CLI.
|
|
This commit adds passing the settings instance to til_setup_new()
which is used for deriving a path for the setup via
til_settings_print_path() on the supplied settings.
That path gets an allocated copy left in the returned
til_setup_t at til_setup_t.path
This path will exist for the lifetime of the til_setup_t, to be
freed along with the rest of the baked setup instance when the
refcount reaches 0.
The incoming til_settings_t is only read @ til_setup_new() in
constructing the path, no reference is kept. Basically the
til_settings_t* is just passed in for convenience reasons, since
constructing the path needs memory and may fail, this approach
lets the existing til_setup_new() call error handling also
capture the path allocation failures as-is turning
til_setup_new() into a bit more of a convenience helper.
Note that now all code may assume a til_setup_t has a set and
valid til_setup_t.path, which should be useful for context
creates when a setup is available.
|
|
Commit 7c8086020 switched the til_setup_new() api to support NULL
free_func for free().
This mechanical change pivots to that instead of the awkwardly
cast free() parameters.
|
|
When voronoi is overlayed the colors get sampled, so randomizing
them is pointless work every frame.
|
|
This seems to work on my 2c/4t laptop and is certainly faster.
But I'm not being careful about using atomics loading/storing the
d->cell pointer, which seems problematic. Surprisingly things
aren't crashing here despite that, maybe on a non-x86 smp box
it'd be a different story.
|
|
Preparatory commit for doing the voronoi distance calculations in
parallel when possible, as part of render_fragment() instead of
all in prepare_frame().
Not all of the distance calculation work can easily be threaded,
but it should be possible to compute the post-seed distances
concurrently within the spatial bounds of the tiled fragment.
This commit doesn't actually change anything functionally, as
it's just splitting the old voronoi_calculate_distances() into
two and calling them both in succession still from
voronoi_prepare_frame().
Subsequent commits will work towards making the render_pass()
fragment-aware then ultimately moved to voronoi_render_fragment()
|
|
This variant is kind of a broken hack, and its brokenness becomes
more apparent in a threaded voronoi world.
So just drop it for now.
I am interested in more voronoi variants, but they can't
compromise correctness/introduce instabilities or significantly
interfere with performance improvements like threaded rendering.
The dithered-ish look of dirty=on was an interesting variant
though... bummer.
|
|
trivial change; voronoi_sample_colors() only reads from the fragment
|
|
Like modules/checkers required for fill_module, we need to do the
same for for rtv::snow_module.
There's more work to do on rtv::channels, but that's still
unsettled stuff in terms of settings syntax since rtv randomizes
settings. It's desirable to have the rtv settings able to
specify which settings to hold constant at a specific value
per-channel, leaving everything else for randomizing on channel
switch.
But there's no syntax for that kind of stuff currently, and it
seems like there's a need to communicate during the setup_func
dance when we're in a "settings optional because we'll fill them
in automatically at time of use later" to the front-end.
It's not strictly a front-end issue though - because the back-end
setup_func actually controls the forward progress. From the
current setup_func's perspective, everything's important to it
and must be fulfilled. And we certainly want the setup_func to
continue informing the setup process.
So it's more like the channel settings being populated via rtv
still need to all get populated, rtv just needs a way to add an
attribute to mark which settings are static vs. which should get
randomized on every use.
Perhaps there should just be a special value syntax reserved for
saying "random value" and the front-end can apply that, but then
a til_module_randomize_setup() could detect that too in a
per-setting flag the front-end set. That way the value gets
re-randomized, while the ones without that value set get left
alone.
Yes, I know this isn't the appropriate place for such commentary.
But nobody is reading these things anyways on my toy side project.
|
|
|
|
This is harmless as long as rtv stays hermetic.
But if rtv gets used in a composite scenario in the future by
either removing the hermetic flag, or allowing forced overrides,
n_cpus=0 will cause the nested module contexts to become threaded
on SMP machines.
That's problematic if the outer module context is already a
threaded render. What's appropriate here is to just propagate
the n_cpus down so if an upper layer has already gone threaded,
it will be sending down n_cpus=1 to serialize the nested
instances.
In practice, as-is, this change basically changes nothing, but
prepares for a potential future where rtv participates in
threaded compositions.
Through a lens of "rtv just rejiggers scenes and there settings
on a timer from a settings-specified subset of modules and
settings" it's arguably useful as just another module. Sometimes
you want something to change itself up periodically in say a
compose layer.
So preparing for this possibility isn't really all that
far-fetched/hypothetical.
|
|
This commit introduces setting path printing to interactive
setup, making it much more clear what on earth you're setting up
in more complex scenarios.
e.g. an interactive setup of module=compose is now:
```
$ src/rototiller --module=compose
/module/compose/layers:
Comma-separated list of module layers, in draw-order [drizzle,stars,spiro,plato]:
/module/compose/layers/[0]/drizzle/viscosity:
Puddle viscosity:
0: .005
1: .01
2: .03
3: .05
Enter a value 0-3 [1 (.01)]:
/module/compose/layers/[0]/drizzle/style:
Overlay style:
0: mask
1: map
Enter a value 0-1 [0 (mask)]:
/module/compose/layers/[1]/stars/rot_adj:
Rotation rate:
0: .0
1: .00001
2: .00003
3: .0001
4: .0003
5: .001
Enter a value 0-5 [2 (.00003)]:
/module/compose/layers/[3]/plato/orbit_rate:
Orbit rate and direction:
0: -1
1: -.75
2: -.5
3: -.25
4: .1
5: 0
6: .1
7: .25
8: .5
9: .75
10: 1
Enter a value 0-10 [7 (.25)]:
/module/compose/layers/[3]/plato/spin_rate:
Spin rate and direction:
0: -1
1: -.75
2: -.5
3: -.25
4: .1
5: 0
6: .1
7: .25
8: .5
9: .75
10: 1
Enter a value 0-10 [9 (.75)]:
/module/compose/texture:
Module to use for source texture, "none" to disable:
0: none
1: blinds
2: checkers
3: drizzle
4: julia
5: moire
6: plasma
7: roto
8: stars
9: submit
10: swab
11: voronoi
Enter a value 0-11 [0 (none)]: 1
/module/compose/texture/blinds/orientation:
Blinds orientation:
0: horizontal
1: vertical
Enter a value 0-1 [0 (horizontal)]:
/module/compose/texture/blinds/count:
Blinds count:
0: 2
1: 4
2: 8
3: 12
4: 16
5: 24
6: 32
Enter a value 0-6 [4 (16)]: 3
/video:
Video backend:
0: drm
1: mem
2: sdl
Enter a value 0-2 [2 (sdl)]:
/video/sdl/fullscreen:
SDL fullscreen mode:
0: off
1: on
Enter a value 0-1 [0 (off)]:
/video/sdl/size:
SDL window size [640x480]:
Configured settings as flags:
--seed=0x6471f827 '--module=compose,layers=drizzle\\\,viscosity\\\=.01\\\,style\\\=mask\,stars\\\,rot_adj\\\=.00003\,spiro\,plato\\\,orbit_rate\\\=.25\\\,spin_rate\\\=.75,texture=blinds\,orientation\=horizontal\,count\=12' '--video=sdl,fullscreen=off,size=640x480'
Press enter to continue, add --go to skip this step...
```
Previously it would be like so:
$ src/rototiller --module=compose
Comma-separated list of module layers, in draw-order [drizzle,stars,spiro,plato]:
Puddle viscosity:
0: .005
1: .01
2: .03
3: .05
Enter a value 0-3 [1 (.01)]:
Overlay style:
0: mask
1: map
Enter a value 0-1 [0 (mask)]:
Rotation rate:
0: .0
1: .00001
2: .00003
3: .0001
4: .0003
5: .001
Enter a value 0-5 [2 (.00003)]:
Orbit rate and direction:
0: -1
1: -.75
2: -.5
3: -.25
4: .1
5: 0
6: .1
7: .25
8: .5
9: .75
10: 1
Enter a value 0-10 [7 (.25)]:
Spin rate and direction:
0: -1
1: -.75
2: -.5
3: -.25
4: .1
5: 0
6: .1
7: .25
8: .5
9: .75
10: 1
Enter a value 0-10 [9 (.75)]:
Module to use for source texture, "none" to disable:
0: none
1: blinds
2: checkers
3: drizzle
4: julia
5: moire
6: plasma
7: roto
8: stars
9: submit
10: swab
11: voronoi
Enter a value 0-11 [0 (none)]: 1
Blinds orientation:
0: horizontal
1: vertical
Enter a value 0-1 [0 (horizontal)]:
Blinds count:
0: 2
1: 4
2: 8
3: 12
4: 16
5: 24
6: 32
Enter a value 0-6 [4 (16)]: 3
Video backend:
0: drm
1: mem
2: sdl
Enter a value 0-2 [2 (sdl)]:
SDL fullscreen mode:
0: off
1: on
Enter a value 0-1 [0 (off)]:
SDL window size [640x480]:
Configured settings as flags:
--seed=0x6471f827 '--module=compose,layers=drizzle\\\,viscosity\\\=.01\\\,style\\\=mask\,stars\\\,rot_adj\\\=.00003\,spiro\,plato\\\,orbit_rate\\\=.25\\\,spin_rate\\\=.75,texture=blinds\,orientation\=horizontal\,count\=12' '--video=sdl,fullscreen=off,size=640x480'
Press enter to continue, add --go to skip this step...
```
Which gets rather confusing, especially if you go even deeper
with nested module situations like
compose/layers/[0]/checkers/fill_module/compose/layers/[0]/drizzle
You just lose track of which module instance's settings you're
actually setting up
This is just the first step of making use of these paths. In the
future the module context paths will be derived from the settings
paths so they're more reliably distinct and descriptive, along
with consistent with paths in the settings namespace. That
becomes important when module contexts start getting registered
on the stream for use in other modules.
|
|
These print to a stdio FILE*, which for now is harmless since
setup_interactively() will be the only consumer (... for now).
If one needed the path in a buffer, they could use
open_memstream() and pass that FILE* to the printers. And since
commit 40feb61 there's already a dependency on the function, but
it's icky to dig deeper into that portability trap.
Although it seemed like rototiller actually compiled on MacOS at
Gene's house, so maybe open_memstream() isn't as problematic as
it once was.
Anywhow, this commit only adds the path printing helpers, nothing
is using them yet.
|
|
Currently settings instances get labels from three sources:
1. explicitly labeled by a root-level til_settings_new() call,
like main.c::til_settings_new(NULL, "video", args->video);
2. implicitly labeled in a spec.as_nested_settings w/spec.key
3. positionally labeled in a spec.as_nested_settings w/o spec.key
But when constructing setting/desc paths, using strictly these
settings instance labels as the "directory name path component"
equivalent, leaves something to be desired.
Take this hypothetical module setting path for example:
/module/layers/[0]/viscosity
Strictly using settings instance labels as-is, the above is what
you'd get for the drizzle::viscosity setting in something like:
--module=compose,layers=drizzle
Which is really awkward. What's really desired is more like:
/module/compose/layers/[0]/drizzle/viscosity
Now one way to achieve that is to just create more settings
instances to hold these module names as labels and things would
Just Work more or less.
But that would be rather annoying and heavyweight, when what's
_really_ wanted is a way to turn the first entry's value of a
given setting instance into a sort of synthetic directory
component in the path.
So that's what this commit does. When a spec has .as_label
specified, it's saying that path construction should treat this
setting's value as if it were a label on a settings instance.
But it's special cased to only apply to descs hanging off the
first entry of a settings instance, as that's the only scenario
we're making use of, and it avoids having to do crazy things like
search all the entries for specs w/.as_label set.
It feels a bit janky but it does achieve what's needed with
little pain/churn.
|
|
7ff8ef94 switched things to always describe relevant settings,
but left some loose ends. Obvious fixups for those
|
|
In this "all settings require descs" world, when setup_func
forgets to return a res_desc for a setting it wants, we can end
up in an infinite loop situation. It's better to abort
immediately on the assert to catch such a program error.
|
|
Like modules/checkers required for fill_module, we need to do the
same for for compose.
It's a little more weird in compose since compose::layers is a
nested settings full of unnamed nested settings.
But compose::texture is analogous to checkers::fill_module.
|
|
The bare-value value_as_nested_settings.entries[0] setting which
serves as the name for module lookup is in a sort of no-mans land
between checkers and the underlying fill_module's setup.
So we have to do this little bit of rigamarole in checkers, being
the entity wiring up the nested module. The fill_module's
setup_func won't be doing anything to describe the name's
setting as it's only interested in its own settings.
There will likely be some helpers made later to streamline this
process of composing module/settings hierarchies.
|
|
Since these are ultimately intended for use in path construction,
it's redundant to include the settings->label in the generated
label. Instead what's really useful is just the subscript part:
/module/compose/layers/layers[0]/drizzle/viscosity
Becomes:
/module/compose/layers/[0]/drizzle/viscosity
which is far better. It may seem silly to have both the
positional subscript *and* the module name, as in why not just
have:
/module/compose/layers/drizzle/viscosity
But there's a need ot handle potential collisions like so:
/module/compose/layers/[0]/drizzle/viscosity
/module/compose/layers/[1]/stars
/module/compose/layers/[2]/drizzle/viscosity
So then maybe you think; ok, why have the module name? just use
the positional subscript since that alone prevents the
collisions. Result:
/module/compose/layers/[0]/viscosity
...
/module/compose/layers/[2]/viscosity
Well, now we've lost useful context. The viscosity setting
recurs on multiple modules, and we don't know just at a glance
what we're working with anymore.
Hence, why there's both. The module name in the path makes
things substantially more self-explanatory. These paths will
likely be what you're looking at as the labels of tracks in a
multitrack sequencer like GNU Rocket. So this decision is likely
affecting the UX at that level in the fullness of time.
|
|
Since 1a8abe80dabd this ceased to be the right thing to do, since
there's no longer the whole bare-key setting with null value.
It's now always a value, and the key that's optional.
|
|
Preparatory for constructing unique paths from a given
setting/settings instance by walking up the tree
|
|
Using on/off for boolean settings is the established convention
in rototiller, rtv went rogue here.
Just make it consistent
Sometimes it feels like this should be more flexible and support
0/1 yes/no true/false on/off by just having "boolean" typed
settings. But I think it may actually pay off long-term to be so
opinionated here and making serialized settings heirarchies
directly hashable/comparable without major normalization steps
(nothing beyond say... case normalization).
|
|
sig_t collides with some signals-related system header on macos.
Just prefix it under the sig namespace.. leaving sig_ops alone
for now, but maybe they'll become sig_sig_ops in the future too.
Note nothing in master actually uses libs/sig currently, but I
have an experimental branch with a dusty module using it.
|
|
Without this mac builds w/brew must be falling through the
single CPU default linux failure code.
|
|
this oversight becomes apparent when stacking checkers as compose
layers w/random pattern and/or dynamics. The stacked instances
would identical pseudo-random behaviors for lack of seeding.
|
|
These were being supplied backwards to til_module_context_new(),
which mostly just meant the seed always started @ 0 for early
checkers contexts, or were just slightly different ticks values
for later ones.
|
|
3b6e34e70 broke this with what looks to be a silly mistake in
modifying the existing put_pixel() calls.
Kept the fragment->{x,y} instead of removing those and keeping
the bare {x,y}.
|
|
These are expected to match, and it's asserted as such in various
fragmenters. Especially now that we're getting more exuberant
with recursive settings/modules, the correctness of the checkers
cells fragment is becoming more exercised/important.
|
|
til_fb_fragment_get_pixel_clipped() was clipping to the frame
bounds, which are actually just a logical dimension for placing
and scaling fragments within a frame. drizzle in particular is
leaning on this clipped-get to prevent accessing outside of the
fragment's backing buffer. Let's just clip it to the fragment
bounds instead, see comment added for more information.
|
|
As-is it's not great for rtv to randomly wind up in compositions,
see comment in commit for more context.
|
|
Commit d72e924a introduced skipping experimental modules for the
values, but it didn't bring in a new index for storing the values
so the offset w/skips was being used to store the values too.
This created a sparse set of values for the setup, manifesting as
a wonky partial interactive setup for the module that didn't even
include the default 0 (rtv) value in the list.
Simple fix.
|
|
til_settings_free() needs to recur on nested settings
|
|
settings->settings[] is obnoxious
largely mechanical rename to settings->entries[]
|
|
first step towards settings-izing rtv, channels[] remains
|
|
Now layers= is a settings instance. Each individual setting
within that layers instance is also a settings instance of its
own.
This enables specifying the modules used in the layers as well as
settings to be passed into those per-layer modules.
The escaping quickly becomes brutal if hand-constructing, but
programmatically at least it's workable. Plus, you can let the
interactive setup ask you for all the layer settings then just
copy and paste the cli invocation printed @ startup (at least
with rototiller).
texture= is also now a settings instance, which means compose no
longer randomizes the texture settings on its own - it instead
uses the settings supplied. A consequence of this is that
texture settings need to be actually populated if the texture is
used.
For rtv, which randomizes settings, it makes no difference and
rtv compose invocations w/textures will just end up randomizing
the texture through the normal setup randomizing machinery.
But for direct compose invocations for instance, there's now an
actual texture setup process - and if you just use --defaults,
the defaults will be applied which is different from before where
it would have always been randomized.
This area needs some work, like controlling how defaults are
applied perhaps in the actual settings syntax such that
randomizing can still be performed if desired instead of
"preferred" defaults. That's a more general settings syntax
problem to investigate
|
|
fill_module= now takes a settings string, so you can specify not
just the name of the module, but additional settings passed into
that module's setup.
The fill_module's context path is also now getting fill_module
appended, but see the large comment surrounding that mess WRT
checker's per-cpu fill_module context creations.
|
|
With setup refcounting and a reference bound to the context, we
should just dereference the single instance. The way setups are
used it just as a read-only thing to affect context behavior...
Note I've left the module-type-specific setup pointer despite it
duplicating the setup pointer in the module_context. This is
just a convenience thing so the accessors don't have to cast the
general til_setup_t* to my_module_setup_t* everywhere.
|
|
This just does the obvious pulling in of til_setup_t, holding the
reference throughout the lifetime of the module context.
|
|
The whole point of til_setup_t is to represent the baked, most
conveniently usable form of a setup derived from one or more
settings instances. Things generally go from the serialization
format "settings string" to til_settings_t eventually culminating
in a til_setup_t.
So the process of making a til_setup_t is rather tedious and kind
of costly. Once into a til_setup_t it's desirable to just hang
on to this form and reuse it if possible. The way a til_setup_t
baked setup is put to use is in a read-only fashion where it
basically just informs behavior, so it makes a lot of sense to
enable refcounting the thing and letting whatever can make use of
it bump the refcount and hold onto the pointer, accessing the
contents whenever it needs to answer a question about that
particular setup.
The immediate impetus for this is actually rtv's snow_module
setup. In rtv every channel switch may recreate the context, if
the context has expired. In the case of the snow module, the
context always expires, and we definitely want to discard the
context while playing the next channel. But when the snow
resumes, in order to recreate the context as configured, we need
the same setup again. It just becomes clear that what's needed
is a way to pin the snow_module's setup for this reuse to be
safe.
There's also plenty of other modules that have been piecemeal
copying settings into their context, when what would really make
more sense is to just ref it and stow the pointer, then unref on
their context destroy. They can just access the setup via the
pointer as needed, instead of having to duplicate the setup in
their context. Indeed, some module contexts even embed the
entire setup just to copy its contents over by value. In
simple/small scenarios that's fine, and I'm sure in those
particular cases it's perfectly safe to do. It just seems
unnecessary altogether.
Another small change made is supporting NULL free_func, which
will default to libc's free(). Most til_setup_new() call sites
are passing free() with an annoying cast, those can be changed to
NULL.
|
|
There was a time when it made sense for context creates needing
setups but not receiving them to still be functional with some
sane defaults.
But with recursive settings, we really shouldn't ever have
orphaned nested module uses unreachable by a proper setup.
So let's just get rid of this fallback, and exclusively rely on
the baked setups provided by the .setup() methods. They still
have preferred defaults, and the proper setup production
machinery is what should be responsible for applying those
at runtime where they may also be overridden or otherwise
influenced.
|
|
If the module has a .setup() method, it should be able to just
blindly expect a valid baked setup to come in @ context create.
Let's enforce that here, and let the module code providing setup
hooks just go forth and access the setup assuming it's at least
present and as valid as their setup method produces.
|
|
This introduces a boolean style log_channels= setting for
enabling logging of channel settings on channel switch.
It might be nice to change this to accept stdout/stderr/fdnum as
the setting instead of always directing at stderr.
This also doesn't capture the seed state so it's not exactly
logging everything needed to reproduce wholly what is being
shown. Some compositions depend more on rand than others, so
it matters at varying degrees.
It'd be nice for settings syntax to have some global syntax
supported where a seed can always be embedded to be loaded.
Introducing such things as global settings to the settings syntax
is a pending TODO item... right now the only way to load seed
state is at startup passed to main as --seed=. That's not gonna
cut it long-term.
This is an easy big step in the right direction though. Trying
to make sense of what's on-screen from the truncated captions is
impossible. Even if the captions wrapped the settings, it would
be tricky to catch the settings without recording the output or
screenshotting.
This also immediately makes me wonder about the voting system for
rtv where we log settings of favorites... then roll those into
playlists.
|
|
This probably needs more work, but it's good enough for now
|
|
It'll be perfectly normal to turn bare-value settings int nested
instances. In such scenarios we don't have a static
spec-supplied key for the label, so let's just generate a label
like a C-style array subscript for such instances.
|
|
When there's a bare-value setting turned into a nested settings
instance, there's no key onhand for labeling the instance.
But such nameless settings are basically array elements only
positionally accessed. This helper produces labels in that style
for such settings by taking the container settings label and
adding [$idx] to the end.
These labels aren't really used as more than a debugging aid at
the moment. But module contexts already have paths in main, and
it seems like these settings instance labels will likely become
the name components in constructing those paths.
|
|
Currently in rototiller the only (de)serialization format of
settings is the args strings, so this is a rather critical piece
to get in for recursive settings to really be usable.
This is a quick and dirty implementation utilizing
open_memstream() which despite being POSIX has spotty support (I
don't think MacOS has it for instance). So that's probably
something to rip out in the future.
Nonetheless, this moves things forward and works fine on GNU.
|
|
This commit pivots everything over to using desc->container as
the target settings instance when adding settings, as well as
actually assigning the settings container @ desc create.
Given nothing is actually triggering settings heirarchies yet (no
specs set as_nested_settings) this shouldn't actually result in
any realized functional difference, yet. The settings pointer
being placed in desc->container should be identical to what was
getting used before.
|
|
There needs to be more flexibility in the value checking
enforcement.
This is just a quick blunt-hammer fix to not trip over nested
settings values which will be huge undeterministic messes vs.
what's likely just a set of simple presets in the spec.values[]
The individual leaf settings will still be checked if they
specify values. So this change just stops even bothering to
check unless the setting is a leaf.
This area needs more work in general, see comments.
For instance right now we can't just pass in arbitrary floats for
settings which list float values, not if that arbitrary float
isn't a member of the list. In some circumstances that's the
right thing to do, as in the module can only work with the
presets.
But most of the time, the module would be perfectly happy with e.g.
foo=.3379 with foo's spec.values[] = { .01, .1, .25, .75, 1} so
the check fails. That's dumb, and interferes with the creative
process when you're just poking different numbers into the
settings to see what happens.
TODO
|