Age | Commit message (Collapse) | Author |
|
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
|
|
Getter for accessing til_settings_t.num
With recursive settings modules will start using settings
instances to represent things like lists of module names.
(modules/compose::layers for instance)
For those cases they'll want to know the number of settings in
the instance before iterating across getting their values
positionally.
|
|
For recursive settings the individual setting being described
needs to get added to a potentially different settings instance
than the one being operated on at the top of the current
setup_func phase.
The settings instance being passed around for a setup_func to
operate on is constified, mainly to try ensure modules don't
start directly mucking with the settings. They're supposed to
just describe what they want next and iterate back and forth,
with the front-end creating the settings from the returned descs
however is appropriate, eventually building up the settings to
completion.
But since it's the setup_func that decides which settings
instance is appropriate for containing the setting.. at some
point it must associate a settings instance with the desc it's
producing, one that is going to be necessarily written to.
So here I'm just turning the existing til_setting_desc_t to a
"spec", unchanged. And introducing a new til_setting_desc_t
embedding the spec, accompanied by a non-const til_settings_t*
"container".
Now what setup_funcs use to express settings are a spec,
otherwise identically to before. Instead of cloning a desc to
allocate it for returning to the front-end, the desc is created
from a spec with the target settings instance passed in.
This turns the desc step where we take a constified settings
instance and cast it into a non-const a more formal act of going
from spec->desc, binding the spec to a specific settings
instance. It will also serve to isolate that hacky cast to a
til_settings function, and all the accessors of
til_setting_desc_t needing to operate on the containing settings
instance can just do so.
As of this commit, the container pointer is just sitting in the
desc_t but isn't being made use of or even assigned yet. This is
just to minimize the amount of churn happening in this otherwise
mostly mechanical and sprawling commit.
There's also been some small changes surrounding the desc
generators and plumbing of the settings instance where there
previously wasn't any. It's unclear to me if desc generators
will stay desc generators or turn into spec generators. For now
those are mostly just used by the drm_fb stuff anyways, modules
haven't made use of them, so they can stay a little crufty
harmlessly for now.
|
|
The core thing here is rather than turning a bare value into a
key as I was doing before - we just leave the bare value as a
bare value and its setting must be located positionally via
get_value_by_idx since there's no key.
Existing callers that used to get_key() positionally now
get_value_by_idx() positionally all the same, except it's the
value instead of the key. This is mostly done for things like
the module or fb name at the front of a settings instance.
The impetus for this change is partially just
cosmetic/ergonomics, but it's also rather strange for what's
really a key-less value to be treated as a value-less key. It
was also awkward to talk/reason about on the road to recursive
settings where bare values would be supported as a standalone
settings instance if properly escaped...
This also adds unescaping of keys, and adds a dependency on the
somewhat linux-specific open_memstream() which may need changing
in the future (see comments).
|
|
setup_func isn't formally defined for libtil, but
setup_interactively() defacto establishes it and
til_module_t.setup() reflects the same signature and calling
convention except with til_settings_t constified.
This change makes them all consistent in this regard, but there
should probably be a formal typedef added for the function.
The reason for constifying this is I don't want setup functions
directly manipulating the settings instance. In the case of
rototiller::setup_interactively() we ensure the stdio-based
interactive setup is always the side doing the manipulation of
the settings. For a libtil-user like glimmer, it's slightly
different beast with GTK+ in the loop, but by preventing the
setup_funcs from messing directly with the settings (instead
having to describe what they want done iteratively), the
front-end always gets its opportunity to maintain its state while
doing the described things.
Of course, this is mostly a lie, and within libtil the constified
til_settings_t gets cast away to modify it in places. But
keeping that limited to within libtil is tolerable IMO. We just
don't want to see such casts in module code.
|
|
Preparatory commit for recursive settings going cray-cray with
escaping. At least single-quote these so it's directly
copy-and-pasteable into a shell prompt.
|
|
When this is set, the setting is itself to be a settings instance
that the frontend must create and place in the relevant
til_setting_t.value_as_nested_settings.
This commit implements that frontend portion in
setup_interactively() for the rototiller frontend.
No setup_func() yet attempts to make use of this stuff. There's
probably more change needed before that can happen, specifically
the setup_func() likely must always produce a til_settings_t* to
indicate which settings instance is currently relevant to the
frontend. Without setup_func() telling the frontend, the
frontend has basically no other way of knowing when the backend
setup_func() has moved up/down the heirarchy at the current
iteration.
|
|
Preparatory commit for settings hierarchies.
|
|
This adds a mandatory label string to til_setttings_new() and
updates call sites accordingly.
For now the root-level settings created by main.c are simply
named "module" and "video" respectively. Any nested settings
creations on behalf of modules will be labeled using the module's
name the settings are being created for use with.
This might evolve with time, for now it's just a minimum churn
kind of decision. I can see it changing such that the top-level
settings also become labeled by the module/video driver name
rather than the obtuse "module" "video" strings.
How these will be leveraged is unclear presently. At the least
it'll be nice to have a label for debugging til_settings_t
heirarchies once recursive settings support lands. In a sense
this is a preparatory commit for that work. But I could see the
labels ending up in serialization contents as markup/syntactic
sugar just to self-document things as well.
There might also be a need to address til_settings_t instances in
the settings heirarchy, which may be something like a
"label/label/label/label" path style thing - though there'd be a
need to deal with name collisions in that approach.
I'm just thinking a bit about how knobs will become addressed
when those become a real thing. The settings label heirarchy
might be the convenient place to name everything in a tree, which
knobs could then inherit their parent paths from under which
their respective knob labels will reside. For the whole name
collision issue there could just be some builtin settings keys
for overriding the automatic module name labeling, something
like:
--module=compose,layers=checkers\,label=first\,fill_module=shapes:checkers\,label=second\,fill_module=shapes
would result in:
/module/first/shapes
/module/second/shapes
or in a world where the root settings weren't just named "module"
and "video":
/compose/first/shapes
/compose/second/shapes
then if there were knobs under checkers and shapes, say checkers
had a "foo" knob and checkers had a "bar" knob, they'd be under
.knobs in each directory:
/compose/first/.knobs/foo
/compose/first/shapes/.knobs/bar
/compose/second/.knobs/foo
/compose/second/shapes/.knobs/bar
something along those lines, and of course if compose had knobs
they'd be under /compose/.knobs
This is just a brain dump and will surely all change before
implemented.
|
|
Existing code was passing 0 which turns into the number of
cores/threads.
That's fine when compose isn't running nested in an already
threaded render, but falls down in something like checkers
w/fill_module=compose since checkers is already threading. But
when checkers creates its fill_module context, it's careful to
pass 1 for n_cpus to prevent that kind of thing. With this
change that no longer falls apart.
|
|
Finishes build/fs part of modules/rocket->modules/rkt rename
started in previous commit.
|
|
It's annoying to have the til module called rocket, and the sync
tracker protocol/library called rocket, so let's at least
differentiate it in code/comments/textual discussion.
Plus this results in shorter module context paths i.e.:
/rkt:scene
/rkt/compose/drizzle:rain
/rkt/compose/drizzle:viscosity
/rkt/compose/plato:spin_rate
/rkt/compose/plato:orbit_rate
vs.
/rocket:scene
etc...
These names are shown in the editor, and they'll tend to be long
but let's at least get the root name down to three chars this
way.
A rename of the files and build system update will come in a
subsequent commit
|
|
Upstream merged my TCP_NODELAY PR, so let's get it in rototiller.
Note I'm blindly setting USE_NODELAY now, but it might actually
break the build for win32 - still need to test that.
|
|
With taps more or less fully implemented, it seems appropriate to
get rid of the stubbed out knobs for now.
Taps don't express the same things about range and usage knobs
aspired towards, but they don't preclude adding such things
either. But it seems clear that the way knobs were stubbed won't
be complementing taps as things stand currently to add those
aspects.
|
|
There should probably be others for the ball radiuses, and colors
|
|
this needs more work to really be useful...
clockstep should be tapped, there should probably be a T tap to
control the emitters' cycle
im doubtful how useful this module will generally be though. It
really needs interactions with other things, like fluid going
around pixbounce
|
|
Just some obvious taps...
Note the actual usable range for viscosity is quite small, like
no greater than .05 really works. There still needs to be some
way to describe bounds on the taps, that or normalizing things to
always be 0-1 or -1..+1 kind of thing, and expecting the modules
or the tap api to map those to the sane ranges.
Just leave everything raw for now, wiring up the taps at least
opens up experimentation and getting a feel for what makes most
sense.
|
|
Part of me wants to give the blinds arbitrary angle instead of
the vert/horiz options. But part of the beauty of blinds is the
jaggy-free aliasing-free sharp edges by virtue of always being
orthonormal using whole pixels.
Maybe in the future there could be a orientation setting where
you pick horiz/vert/angular. Then only when angular does it get
a theta tap and use angled blinds with anti-aliased imperfect
edges...
|
|
This adds a rudimentary but functional rocket module for
sequencing "tapped" variables in rototiller modules according to
a timeline via GNU Rocket editors.
Currently this only supports a single seq_module= as a setting
which will be used for rendering. Any tapped variables present
in the nested modules under seq_module will be available for
sequencing, and should automatically appear in a connected rocket
editor.
If you specify connect=off then rocket sync tracks will be read
from the filesystem if present. It's a bit clumsy as-is due to
how the GNU Rocket library handles this currently. There's a
"base" label concept for the virtual rocket device, and the
tracks are intended to be files in a directory named using that
base= setting.
The way you create those track files is by triggering a remote
export from the editor while connected. The location of the
directory is relative to the cwd of the rototiller process, and
you can't specify absolute paths as the base= setting to be
explicit about where things go. The setting isn't really a path,
as that's not what the library wants it to be. It's an area in
need of improvement.
In any case, as long as you start with the same base= setting,
from the same CWD, as when you did the remote export, you can
re-run with connect=off and the exported tracks will be used
automagically and things should replay without the editor
connected.
If you start with connect=on, which is the default, you need to
have the editor already running. Otherwise the rocket module
will fail @ context create, and you'll get a confusing error
about being unable to allocate memory. This is just for now, the
context create needs to start returning an errno instead of just
the context pointer so the error messages can be more informative
now that context create may be doing complicated things like
connecting to sockets.
Another thing to improve is probably having the module just
reconnect periodically if connect=on but it failed @ context
create. It could just start anyways and not fail the context
create at all there, and just start working once you get the
editor online. That'd be a better user experience.
This is a good first step regardless...
|
|
This just stubs out a rocket meta module that renders with
another module.
Future commits will integrate GNU Rocket here.
When recursive settings formally lands you'll be able to nest as
much settings content as necessary for the underlying module
used, as part of the rocket settings. That should enable
describing stuff like complex compose scenarios for rocket to
sequence.
|
|
There needs to be a way for a meta module like rocket to take
ownership of pipes immediately upon instantiation. Since the
pipes are created on demand as they become tapped by the modules
using htem, the simplest way to do this is to register some
callbacks with the ability to intercept the pipe creation in
terms of ownership and driving tap control etc.
This commit forms a minimal implementation of that, with the
ability to have a single intercepter hooked into a given stream.
It's a first-come-first-served situation, but that should suffice
for now since the rocket meta module would be the entrypoint for
such constructions. It then calls into another module to produce
on the stream, after it'll already have its hooks registered.
There might be a need for stacking hooks to let multiple modules
control pipes. GNU Rocket for instance only deals with
floats/doubles, and doesn't make it particularly easy to work on
higher order concepts like say orbiting a vector around a point
spatially. It might make sense to allow compositing of editors
where there's rocket controlling the simple floats, and another
doing dimensional/spatial stuff, with separate stacked meta
modules accomodating those editors. But that's putting the cart
before the horse, let's do the stupid simple thing for now and
see what this is like.
|
|
The driving tap's owner and pipe's owner are decoupled. When
tearing down an owner from a stream, any pipes its taps are
driving should also just go away. Otherwise its taps could
linger on pipes it doesn't own, which would be a UAF bug.
If the pipe is still needed, it'll just get recreated by another
tap. So there's a small perf hit, but this shouldn't be a
continuos kind of occurrence.
|
|
Some clarifications
|
|
|
|
When a driving tap becomes inactive, til_stream_tap() should be
able to notice and replace the driver.
An example driving tap becoming inactive would be a GNU Rocket
track that once had keys in it, but then had them all deleted.
This should set the inactive flag so the tap's automation can
take over. This gives the user at the Rocket editor the ability
to both take over from the tap automation and surrender control
back, by populating vs. emptying the respective track.
|
|
In order to implement something like a rocket module there needs
to be a way to iterate the pipes in the stream, and take
owernship of them when not already owned by rocket.
The way rocket's API works is you lookup tracks by name at
runtime. The rocket module will be a meta module that calls into
another module for rendering, arbitrarily configured via a rocket
setting a la checkers::fill_module.
So it won't be until the underlying modules do some rendering
that their taps get their respective pipes established in the
stream. Then the rocket module can look at all the pipes and for
any it doesn't own yet, it can get the tracks for those names and
take ownership while stowing the track handle in owner_foo for
the pipe.
While iterating all the pipes, the pipes already owned will have
the tracks readily available which can produce the values to
stick in the tap.
Something like that anyways, the til_stream_t api changes in this
commit are all preparatory for a rocket module.
|
|
Just clarify some verbiage, and actually assert type+n_elems
match. Note mismatch also fallsthrough to an -EINVAL just in
case asserts() have been compiled out (-DNDEBUG).
|
|
It seems likely that pipe owners will need not only a way to
differentiate themselves via the owner pointer, but also
somewhere to register a pipe-specific reference.
There probably needs to be a result pointer added for storing the
owner_foo when the owner taps, so the owner can make use of it.
|
|
We need a way to identify owners of taps when cleaning up
their containing contexts, especially once they're hanging off
streams.
|
|
Let's make it so til_module_context_t as returned from
til_module_context_new() can immediately be freed via
til_module_context_free().
Previously it was only after the context propagated out to
til_module_context_create() that it could be freed that way, as
that was where the module member was being assigned.
With this change, and wiring up the module pointer into
til_module_t.create_context() as well for convenient providing to
til_module_context_new(), til_module_t.create_context() error
paths can easily cleanup via `return til_module_context_free()`
But this does require the til_module_t.destroy_context() be able
to safely handle partially constructed contexts, since the
mid-create failure freeing won't necessarily have all the members
initialized. There will probably be some NULL derefs to fix up,
but at least the contexts are zero-initialized @ new.
|
|
Preparatory commit for experimenting with a GNU Rocket
integration for controlling the stream pipes on a timeline.
Since rocket doesn't support things like arbitrary strings, it's
not a natural fit for rototiller where the obvious thing would be
to describe scene compositions as settings strings as if you were
invoking rototiller.
But a temporary hack might be to just tell a rocket module
up-front all the scenes as settings strings you provide to its
setup. Those get assigned numeric identifiers, then rocket
tracks can control when they come on/off numerically. It just
requires describing all the scenes up front rather than in the
pattern editor which is less than ideal.
Being able to experiment with this half-ass solution may prove
useful anyways, and shouldn't be too much work.
|
|
For strictly logical fragments (e.g. tiled fragmenters) there
won't be any ops, and that's even documented in the comments.
But the snapshot and reclaim functoins were assuming the ops
would be non-NULL. Snapshot in particular trips on this
assumption when a module snapshots a subfragment, like drizzle in
montage. I'm surprised I haven't encountered this crash
before...
|
|
It was assumed (n_modules - n_overlayable) would give the number
of non-overlayable modules appropriate as base layers. But with
the skipping of hermetic and experimental modules the base_idx
could be out of reach leaving layers NULL after the loop, which
will segfault later when strlen() assumes it's non-NULL.
This commit does the simple thing and also counts the unusable
modules to subtract from those eligible for base layers along
with n_overlayable.
|
|
Just some banal paperwork...
|
|
Don't make experimental modules available to the
regular/potentially-interactive setup routine.
There should be a flag like --experimental to generally enable
these.
|
|
As with the other composite modules, if --experimental happens
this will need adjustment to honor it.
For now let's just prevent things from breaking when those
modules start appearing.
|
|
This only omits the modules from the random layers
Note the texture_values list is enumerated in compose_setup,
so there's no corresponding change needed there. It might make
sense to change that to a runtime-discovered list though, I think
that was done in the pre-flags era.
|