Age | Commit message (Collapse) | Author |
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
This allows explicit listing of such modules as channels, while
protecting the automagic/defaults scenario.
If there's a future --experimental flag or such added, then the
TIL_MODULE_EXPERIMENTAL check will have to become conditional on
it.
|
|
This was mostly done out of convenience at the expense of turning
the fragment struct into more of a junk drawer.
But properly cleaning up owned stream pipes on context destroy
makes the inappropriateness of being part of til_fb_fragment_t
glaringly apparent.
Now the stream is just a separate thing passed to context create,
with a reference kept in the context for use throughout. Cleanup
of the owned pipes on the stream supplied to context create is
automagic when the context gets destroyed.
Note that despite there being a stream in the module context, the
stream to use is still supplied to all the rendering family
functions (prepare/render/finish) and it's the passed-in stream
which should be used by these functions. This is done to support
the possibility of switching out the stream frame-to-frame, which
may be interesting. Imagine doing things like a latent stream
and a future stream and switching between them on the fly for
instance. If there's a sequencing composite module, it could
flip between multiple sets of tracks or jump around multiple
streams with the visuals immediately flipping accordingly.
This should fix the --print-pipes crashing issues caused by lack
of cleanup when contexts were removed (like rtv does so often).
|
|
Now that til_stream_t is implemented, let's wire up the taps.
Note that nothing actually creates the stream and puts it in the
fragment yet, so stream is still always NULL for these
effectively turning this into a NOP.
|
|
There needs to be a way to address module context instances
by name externally, in a manner complementary to settings and
taps.
This commit adds a string-based path to til_module_context_t, and
modifies til_module_create_context() to accept a parent path
which is then concatenated with the name of the module to produce
the module instance's new path.
The name separator used in the paths is '/' just like filesystem
paths, but these paths have no relationship to filesystems or
files.
The root module context creation in rototiller's main simply
passes "" as the parent path, resulting in a "/" root as one
would expect.
There are some obvious complications introduced here however:
- checkers in particular creates a context per cpu, simply using
the same seed and setup to try make the contexts identical at
the same ticks value. With this commit I'm simply passing the
incoming path as the parent for creating those contexts, but
it's unclear to me if that will work OK. With an eye towards
taps deriving their parent path from the context path, I guess
these taps would all get the same parent and hash to the same
value despite being duplicated. Maybe it Just Works, but one
thing is clear - there won't be any way to address the per-cpu
taps as-is. Maybe that's desirable though, there's probably
not much use in trying to control the taps at the CPU
granularity.
- when the recursive settings stuff lands, it should bring along
the ability to explicitly name settings blocks. Those names
should override the module name in constructing the path.
I've noted as such in the code.
- these paths probably need to be hashed @ initialization time
so there needs to be a hash function added to til, and a hash
value accompanying the name in the module context. It'd be
dumb to keep recomputing the hash when these paths get used
for hash table lookups multiple times per frame...
there's probably more I'm forgetting right now, but this seems
like a good first step.
fixup root path
|
|
Wiring up some minimal taps to see how this will work...
This only initializes the taps and changes the render to access
the rates indirectly via the tapped pointers.
|
|
Wiring up some minimal taps to see how this will work...
This only initializes the taps and changes the render to access
the rates indirectly via the tapped pointers.
|
|
The existing code only really cared about preserving the incoming
texture on behalf of the caller when the compose code itself was
doing something with the texture.
But there's scenarios where the underlying module being rendered
(or its descendants) might play with the texture, and in such a
situation when the outer compose wasn't involving a texture it'd
let the descandants installed texture leak out to the callers
making the texture apply more than one'd expect.
Arguably none of the modules should be missing restoration of the
incoming texture after installing+rendering with their own. But
with this change in place, compose will clean up after nested
modules leaking their texture up.
|
|
At low framerates, the strobe module timer can expire from frame to
frame. This has the effect of appearing "always on." This condition was
obscuring output in compose mode.
#BirdwalkCommit #WinterStormWarning
|
|
Mechanical rearrangement, but ultimately there probably needs to
be an initialize function added to til_module_t. With all the
threading chaos going on, this approach to implicit
initialization with a static flag is racy without using atomics.
For now it's probably marginally better to do this in context
create vs. prepare frame. Context creates *tend* to happen in
single-threaded phases of execution, and infrequently. Prepare
frame is a serialized phase of the rendering for a given context,
but there can be many contexts in-flight simultaneously now with
all the forms of compositing happening, sometimes from multiple
threads. So that assumption no longer holds...
|
|
This gets rid of the static accumulator hack used for the blinds
phase.
|
|
After reading about the Dreamachine[0], I wanted to experience
this phenomenon. The javascript-based web implementations
struggled to hold a steady 10Hz rate and would flicker like
crazy, so here we are.
Only setting right now is period=float_seconds, defaults to .1
for 10Hz.
One limitation in the current implementation is when the frame
rate can't keep up with the period the strobe will just stick on
without ever going off, because the period will always be
expired. There should probably be a setting to force turning off
for at least one frame when it can't keep up.
[0] https://en.wikipedia.org/wiki/Dreamachine
|
|
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.
|
|
Just looking to spice up plato a bit. It seems to make a lot of
appearances in rtv, or is just one of those highly visible things
when it's participating. Way too monotonous as-is.
|
|
moire makes for an interesting texture, esp. mixed with itself:
--seed=0x62f00a7b --module=compose,layers=julia:moire:drizzle,texture=moire
|
|
this introduces a style= setting with values:
style=mask simple alpha mask overlay
style=map displacement mapped overlay
I might add a lighting option for the style=map mode with a
moving light source or something like that, but it's already
pretty slow as-is.
This is mostly just for more testing of the snapshotting, but
there's some interesting compositions enabled like:
module=compose,layers=submit:moire:drizzle
or just moire:drizzle, when style=map happens.
|
|
This arguably doesn't require snapshotting to work, since it's
doing a rudimentary in-place single pixel alpha-blended
replacement using a single pixel at the same location.
But the moment it startus using multiple adjacent super-samples,
the snapshot becomes necessary. If it gets further complicated
with displacements and maybe bump-mapping or something, then the
samples can become quite distant from the pixel being written,
spreading out into neighboring fragments being rendered
simultaneously etc. These are all cause for snapshotting...
For now though it's a very simple implementation that at least
makes drizzle overlayable, while also providing a smoke test for
the new snapshotting functionality.
|
|
Preparatory commit for enabling cloneable/swappable fragments
There's an outstanding issue with the til_fb_page_t submission,
see comments. Doesn't matter for now since cloning doesn't happen
yet, but will need to be addressed before they do.
|
|
This introduces a bespoke fragmenter for checkers. The generic
til_fb tiler isn't concerned with aesthetics so it doesn't
particularly care if clipped tiles are asymmetrically
distributed. It worked fine to get checkers developed and
working, but it's really unattractive to have the whole be
off-centered when the checkers don't perfectly align with the
frame size.
There's some gross aspects like leaving the frame_{width,height}
to be corrected at render time so render_fragment can access the
incoming frame_width for cell state determination.
|
|
quick and dirty fixup for proper use as checkers fill_module=
note this thing already relies on _checked() put_pixel variant
|
|
s/unchecked/checked/ and use frame dimensions, probably more fixes
needed but this prevents crashing as checkers fill_module= at least.
|
|
Sorry but more s/unchecked/checked/ and now this seems to not
crash when used as a checkers fill_module.
|
|
This is a first approximation of correct handling of arbitrarily
clipped frames described by the incoming fragment.
It's still relying on the _checked() put_pixel variants for
clipping. That should probably be improved by constraining the
loops to the clipped fragment edges.
|
|
These modules have been doing their work in prepare_frame(), but
aren't actually threaded modules and don't return a frame plan
from prepare_frame() nor do they provide a render_fragment() to
complement the prepare_frame().
The convention thus far has been that single-threaded modules
just provide a render_fragment and by not providing a
prepare_frame they will be executed serially.
These two modules break the contract in a sense by using
prepare_frame() without following up with render_fragment().
I'm not sure why it happened that way, maybe at one time
prepare_frame() had access to some things that render_fragment()
didn't.
In any case, just make these use render_fragment() like any other
simple non-threaded module would.
This was actually causing a crash when n_cpus=1 because
module_render_fragment() was assuming the prepare_frame() branch
would include a render_fragment(). It should probably be
asserting as such.
|
|
Wire up seed via til_module_context.seed in the obvious manner,
minimal change to the code, no functional difference besides
giving pixbounces instances an isolated random seed state.
|
|
Normalized all the randomizers to use til_module_context.seed
while in here.
|
|
wired up to til_module_context.seed
|
|
This is a little contorted but not too bad. The input to
particles_new() is just a const conf struct, so instead of
passing in the seed value for particles_t to contain, a pointer
to where the seed lives is passed in via the conf. This requires
the caller to persist a seed somewhere outside the particles
instance, but at least in rototiller we already have that
conveniently in til_module_context_t.
|